<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Nduli's World</title><link href="https://blog.jnduli.co.ke/" rel="alternate"/><link href="https://blog.jnduli.co.ke/feeds/all.atom.xml" rel="self"/><id>https://blog.jnduli.co.ke/</id><updated>2024-07-22T00:00:00+03:00</updated><entry><title>GUIX OS with GeneNetwork</title><link href="https://blog.jnduli.co.ke/guix-os-with-genenetwork.html" rel="alternate"/><published>2024-07-22T00:00:00+03:00</published><updated>2024-07-22T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2024-07-22:/guix-os-with-genenetwork.html</id><summary type="html">&lt;p&gt;Guix OS install involves &lt;a href="https://guix.gnu.org/download/"&gt;downloading the iso&lt;/a&gt;;
setting it on a flash disk with: &lt;code&gt;dd if=guix.iso of=/dev/sdX status=progress&lt;/code&gt;;
and using the graphical guide. Some quirks I got were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I needed an internet connection but wifi didn't work out of the box. I used
  USB tethering …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;Guix OS install involves &lt;a href="https://guix.gnu.org/download/"&gt;downloading the iso&lt;/a&gt;;
setting it on a flash disk with: &lt;code&gt;dd if=guix.iso of=/dev/sdX status=progress&lt;/code&gt;;
and using the graphical guide. Some quirks I got were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I needed an internet connection but wifi didn't work out of the box. I used
  USB tethering though.&lt;/li&gt;
&lt;li&gt;I forgot to edit the final configuration to UEFI. To boot, I used grub by:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# ref: https://superuser.com/a/1512531&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pager&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
ls
&lt;span class="c1"&gt;# find the drive that has guix_os by searching for /etc/config.scm file&lt;/span&gt;
cat&lt;span class="w"&gt; &lt;/span&gt;drive_from_ls/etc/config.scm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# e.g. cat (hd0,1)/etc/config.scm&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;drive_from_ls&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# e.g. set root=(hd0,1)&lt;/span&gt;
cat&lt;span class="w"&gt; &lt;/span&gt;/boot/grub/grub.cfg
&lt;span class="c1"&gt;# run the commands in the menuentry manually&lt;/span&gt;
linux&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/......
initrd&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/.....
&lt;span class="c1"&gt;# boot the OS&lt;/span&gt;
boot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;I changed my bootloader config in &lt;code&gt;/etc/config.scm&lt;/code&gt; to fix the efi issue&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;guix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gnu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;manual&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html_node&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Bootloader&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="c1"&gt;#index-bootloader_002dconfiguration&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;grub&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;efi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(&amp;quot;/boot/efi&amp;quot;))&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and rebuild the OS with &lt;code&gt;sudo guix system reconfigure --allow-downgrades /etc/config.scm&lt;/code&gt;
- I experienced screen flickering in my terminal and modified my boot parameters
  to fix it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;wiki&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;archlinux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Intel_graphics&lt;/span&gt;&lt;span class="c1"&gt;#Screen_flickering&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;grub&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;efi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(&amp;quot;/boot/efi&amp;quot;))&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;i915.enable_psr=0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Quality of Life Changes&lt;/h2&gt;
&lt;h3&gt;Zsh as default shell&lt;/h3&gt;
&lt;p&gt;Change &lt;code&gt;/etc/config.scm&lt;/code&gt; to have:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//lists.gnu.org/archive/html/help-guix/2017-07/msg00024.html&lt;/span&gt;
&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;added&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shells&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cons&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rookie&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rookie&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;users&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/home/rookie&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;added&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;$zsh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/bin/zsh))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;supplementary&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wheel&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;netdev&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;audio&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;vidoe&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nf"&gt;%base&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When installing &lt;code&gt;oh-my-zsh&lt;/code&gt; I also got an error: &lt;code&gt;ZSH not installed&lt;/code&gt; and I had
to do an extra &lt;code&gt;guix install zsh&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Non Guix&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://gitlab.com/nonguix/nonguix"&gt;Non Guix Reference&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For wifi to work, I modified &lt;code&gt;/etc/config.scm&lt;/code&gt; to have:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;non&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;linux&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nongnu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;linux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nongnu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;linux&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;initrd&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operating&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kernel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;linux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firmware&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;linux&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;firmware&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The README did most of the heavy lifting, but I couldn't figure out how to add
the substitutes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xfce&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;desktop&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OpenSSH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;an&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;openssh&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;below&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;openssh&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cups&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;xorg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;
&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xorg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;we&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;appending&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%desktop&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modify&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%desktop&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;
&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guix&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guix&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inherit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;substitute&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://substitutes.nonguix.org&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="nf"&gt;%default&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;substitute&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorized&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plain&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;non-guix.pub&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                                                &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//substitutes.nonguix.org/signing-key.pub&lt;/span&gt;
&lt;span class="w"&gt;                                                &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;
&lt;span class="w"&gt;                                                  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;(public-key (ecc (curve Ed25519) (q #C1FD53E5D4CE971933EC50C9F307AE2171A2D3B52C804642A7A35F84F3A4EA98#)))&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                                                  &lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="nf"&gt;%default&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;authorized&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;guix&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Locale Bug&lt;/h3&gt;
&lt;p&gt;I couldn't get &lt;code&gt;tmux&lt;/code&gt; to start, getting &lt;code&gt;tmux: invalid LC_ALL, LC_CTYPE or LANG&lt;/code&gt;
and running &lt;code&gt;locale -a&lt;/code&gt; failed too. The root cause was that my applications were
built on a different version of &lt;code&gt;glibc&lt;/code&gt; and running &lt;code&gt;guix upgrade&lt;/code&gt; fixed this.&lt;/p&gt;
&lt;h1&gt;GeneNetwork Setup&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://issues.genenetwork.org/topics/guix/guix-profiles"&gt;Follow the instructions here to set up genenetwork&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Small changes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# pick the channels file from &lt;/span&gt;
curl&lt;span class="w"&gt; &lt;/span&gt;https://ci.genenetwork.org/channels.scm&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;channels.scm
&lt;span class="c1"&gt;# gn2 setup&lt;/span&gt;
guix&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;channels.scm&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn2
&lt;span class="nv"&gt;GUIX_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.guix-extra-profiles/gn2
.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$GUIX_PROFILE&lt;/span&gt;/etc/profile
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;genenetwork2&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn2
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;genenetwork3&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# setups an older version&lt;/span&gt;

&lt;span class="c1"&gt;# gn3 setup&lt;/span&gt;
guix&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;channels.scm&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn3
&lt;span class="nv"&gt;GUIX_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.guix-extra-profiles/gn3
.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$GUIX_PROFILE&lt;/span&gt;/etc/profile
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;genenetwork3&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn3
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;genenetwork2&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn3
guix&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;python-mysqlclient&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn3
guix&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;python-pyld&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn3
pytest&lt;span class="w"&gt; &lt;/span&gt;-k&lt;span class="w"&gt; &lt;/span&gt;unit_tests&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# succeeds after this&lt;/span&gt;
pytest&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# still fails&lt;/span&gt;
&lt;span class="nv"&gt;FLASK_DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main.py&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flask&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;--port&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# works&lt;/span&gt;

&lt;span class="c1"&gt;# gn-auth set up is a bit different from the above&lt;/span&gt;
&lt;span class="c1"&gt;# the README is clear in this case&lt;/span&gt;
&lt;span class="c1"&gt;# just make sure you have genenetwork2 and genetwork3 installed in the profile&lt;/span&gt;

guix&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;channels.scm&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn-auth
&lt;span class="nv"&gt;GUIX_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.guix-extra-profiles/gn-auth
.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$GUIX_PROFILE&lt;/span&gt;/etc/profile
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;genenetwork3&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn-auth
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;genenetwork2&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn-auth
guix&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="w"&gt; &lt;/span&gt;--install-from-file&lt;span class="o"&gt;=&lt;/span&gt;guix.scm&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.guix-extra-profiles/gn-auth
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="computer"/></entry><entry><title>Generate HTML when Using Markdown in Vimwiki</title><link href="https://blog.jnduli.co.ke/generate_html_when_using_markdown_in_vimwiki.html" rel="alternate"/><published>2023-09-02T00:00:00+03:00</published><updated>2023-09-02T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2023-09-02:/generate_html_when_using_markdown_in_vimwiki.html</id><summary type="html">&lt;p&gt;I &lt;a href="https://blog.jnduli.co.ke/migrate_from_vimwiki_to_markdown_syntax.html"&gt;moved to &lt;code&gt;markdown&lt;/code&gt;&lt;/a&gt; in
vimwiki but couldn't generate html. &lt;code&gt;VimwikiAll2HTML&lt;/code&gt; only supported vimwiki
syntax. I explored static site generators looking for one that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;didn't require moving my files and folders.&lt;/li&gt;
&lt;li&gt;didn't need a lot of configuration to set up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I tested out &lt;a href="https://www.mkdocs.org/"&gt;&lt;code&gt;mkdocs&lt;/code&gt;&lt;/a&gt;,
&lt;a href="https://www.getzola.org/"&gt;&lt;code&gt;zola&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docusaurus.io/"&gt;&lt;code&gt;docusaurus&lt;/code&gt;&lt;/a&gt; and
&lt;a href="https://vitepress.dev/"&gt;&lt;code&gt;vitepress&lt;/code&gt;&lt;/a&gt; and only …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I &lt;a href="https://blog.jnduli.co.ke/migrate_from_vimwiki_to_markdown_syntax.html"&gt;moved to &lt;code&gt;markdown&lt;/code&gt;&lt;/a&gt; in
vimwiki but couldn't generate html. &lt;code&gt;VimwikiAll2HTML&lt;/code&gt; only supported vimwiki
syntax. I explored static site generators looking for one that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;didn't require moving my files and folders.&lt;/li&gt;
&lt;li&gt;didn't need a lot of configuration to set up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I tested out &lt;a href="https://www.mkdocs.org/"&gt;&lt;code&gt;mkdocs&lt;/code&gt;&lt;/a&gt;,
&lt;a href="https://www.getzola.org/"&gt;&lt;code&gt;zola&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docusaurus.io/"&gt;&lt;code&gt;docusaurus&lt;/code&gt;&lt;/a&gt; and
&lt;a href="https://vitepress.dev/"&gt;&lt;code&gt;vitepress&lt;/code&gt;&lt;/a&gt; and only &lt;code&gt;vitepress&lt;/code&gt; met both conditions.
It also worked out the box and I liked the default theme.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;npm&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-D&lt;span class="w"&gt; &lt;/span&gt;vitepress
npx&lt;span class="w"&gt; &lt;/span&gt;vitepress&lt;span class="w"&gt; &lt;/span&gt;init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;This works with &lt;code&gt;"vitepress": "^1.0.0-beta.3"&lt;/code&gt; in my &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This overrides &lt;code&gt;index.md&lt;/code&gt;, so have a back up. I used git to restore it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I generated the hmtl using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;npx&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;docs:build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The sidebars didn't look great though, and I used
&lt;a href="https://github.com/JonathanSchndr/vitepress-plugin-auto-sidebar/tree/main"&gt;vitepress-plugin-auto-sidebar&lt;/a&gt;
to set this to by my folders. It's config looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;sidebar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getSidebar&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contentRoot&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contentDirs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;team&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;collapsible&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;collapsed&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and this forced me to set up a long list of contentDirs. I instead used an
&lt;code&gt;ignore list&lt;/code&gt; and generated my &lt;code&gt;contentDirs&lt;/code&gt; from code with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EXCLUDE_DIRS&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;node_modules&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;diary&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;scripts&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CONTENT_ROOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getSideBarFolders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;content_root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CONTENT_ROOT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content_root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;withFileTypes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDirectory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;EXCLUDE_DIRS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;changing the plugin's config to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;sidebar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getSidebar&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contentRoot&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CONTENT_ROOT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contentDirs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getSideBarFolders&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;collapsible&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;collapsed&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I added a &lt;code&gt;post-commit&lt;/code&gt; hook that would update my vimwiki site any time I
changed my wiki:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;euo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pipefail&lt;/span&gt;

&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;$(git rev-parse --show-toplevel)&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;
&lt;span class="n"&gt;rsync&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--recursive --archive --update --verbose --compress -P .vitepress/dist/ user@ip:/path/to/folder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Computer"/></entry><entry><title>Migrate From Vimwiki To Markdown Syntax</title><link href="https://blog.jnduli.co.ke/migrate_from_vimwiki_to_markdown_syntax.html" rel="alternate"/><published>2023-07-29T00:00:00+03:00</published><updated>2023-07-29T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2023-07-29:/migrate_from_vimwiki_to_markdown_syntax.html</id><summary type="html">&lt;p&gt;&lt;a href="https://github.com/vimwiki/vimwiki"&gt;Vimwiki&lt;/a&gt; supports markdown and I switched
to this because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I didn't use the default syntax anywhere else.&lt;/li&gt;
&lt;li&gt;I could convert to html using only &lt;code&gt;VimwikiAll2HTML&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fixing My Config&lt;/h2&gt;
&lt;p&gt;Vimwiki expects some options set before it loads
(&lt;a href="https://github.com/vimwiki/vimwiki/issues/935#issuecomment-661647681"&gt;ref&lt;/a&gt;).
With &lt;a href="https://github.com/folke/lazy.nvim"&gt;lazy&lt;/a&gt;, I use &lt;code&gt;init&lt;/code&gt; like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vimwiki/vimwiki&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;branch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dev&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mattn/calendar-vim …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://github.com/vimwiki/vimwiki"&gt;Vimwiki&lt;/a&gt; supports markdown and I switched
to this because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I didn't use the default syntax anywhere else.&lt;/li&gt;
&lt;li&gt;I could convert to html using only &lt;code&gt;VimwikiAll2HTML&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fixing My Config&lt;/h2&gt;
&lt;p&gt;Vimwiki expects some options set before it loads
(&lt;a href="https://github.com/vimwiki/vimwiki/issues/935#issuecomment-661647681"&gt;ref&lt;/a&gt;).
With &lt;a href="https://github.com/folke/lazy.nvim"&gt;lazy&lt;/a&gt;, I use &lt;code&gt;init&lt;/code&gt; like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vimwiki/vimwiki&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;branch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dev&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mattn/calendar-vim&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;vimwiki_list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;~/vimwiki&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;path_html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;~/vimwiki/public_html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;auto_tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;auto_diary_index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;syntax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;markdown&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.md&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;-- experimental folder for markdown conversion&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;~/projects/vimwiki&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;path_html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;~/projects/vimwiki_markdown/public_html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;syntax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;markdown&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.md&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;vimwiki_markdown_link_ext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;vimwiki_stripsym&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;vimwiki_global_ext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Pandoc Conversion&lt;/h2&gt;
&lt;p&gt;I tested &lt;a href="https://pandoc.org/"&gt;pandoc&lt;/a&gt; for conversion with the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;

&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sublist&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usb&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sub1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt;

&lt;span class="nl"&gt;TODO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ve left to address later&lt;/span&gt;

&lt;span class="s1"&gt;I&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;paragraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;[link to file&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;

&lt;span class="err"&gt;{{{&lt;/span&gt;&lt;span class="n"&gt;bash&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;lah&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;iname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*.wiki&amp;#39;&lt;/span&gt;
&lt;span class="err"&gt;}}}&lt;/span&gt;

&lt;span class="n"&gt;Another&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;

&lt;span class="err"&gt;{{{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;lah&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;iname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*.wiki&amp;#39;&lt;/span&gt;
&lt;span class="err"&gt;}}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;code&gt;pandoc --from vimwiki --to commonmark_x trial.wiki&lt;/code&gt; gave me:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;╰─$&lt;span class="w"&gt; &lt;/span&gt;pandoc&lt;span class="w"&gt; &lt;/span&gt;--from&lt;span class="w"&gt; &lt;/span&gt;vimwiki&lt;span class="w"&gt; &lt;/span&gt;--to&lt;span class="w"&gt; &lt;/span&gt;commonmark_x&lt;span class="w"&gt; &lt;/span&gt;trial.wiki
&lt;span class="c1"&gt;## Title {#Title}&lt;/span&gt;

-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;.done2&lt;span class="o"&gt;}&lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;item&lt;span class="w"&gt; &lt;/span&gt;i:
&lt;span class="w"&gt;  &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;.done1&lt;span class="o"&gt;}&lt;/span&gt;sublist
&lt;span class="w"&gt;    &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;.done4&lt;span class="o"&gt;}&lt;/span&gt;sub&lt;span class="w"&gt; &lt;/span&gt;sub
&lt;span class="w"&gt;    &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;.done0&lt;span class="o"&gt;}&lt;/span&gt;sub&lt;span class="w"&gt; &lt;/span&gt;usb
&lt;span class="w"&gt;    &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;.done0&lt;span class="o"&gt;}&lt;/span&gt;sub&lt;span class="w"&gt; &lt;/span&gt;sub1
&lt;span class="w"&gt;  &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;.done4&lt;span class="o"&gt;}&lt;/span&gt;final

&lt;span class="o"&gt;[&lt;/span&gt;TODO:&lt;span class="o"&gt;]{&lt;/span&gt;.todo&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;task&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;

I&lt;span class="se"&gt;\&amp;#39;&lt;/span&gt;m&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;paragraph.

&lt;span class="o"&gt;[&lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="o"&gt;](&lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;wikilink&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="sb"&gt;```&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bash
&lt;span class="w"&gt;  &lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;-lah
&lt;span class="w"&gt;  &lt;/span&gt;find&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;-iname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*.wiki&amp;#39;&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

Another&lt;span class="w"&gt; &lt;/span&gt;code&lt;span class="w"&gt; &lt;/span&gt;block

&lt;span class="w"&gt;      &lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;-lah
&lt;span class="w"&gt;      &lt;/span&gt;find&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;-iname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*.wiki&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I had these problems with the conversion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the checklist generated wouldn't work with vimwiki&lt;/li&gt;
&lt;li&gt;I didn't want the escaped &lt;code&gt;'&lt;/code&gt;  character in my files&lt;/li&gt;
&lt;li&gt;The link to a file had the string "wikilink" which wouldn't work in vimwiki&lt;/li&gt;
&lt;li&gt;I lost my comment&lt;/li&gt;
&lt;li&gt;The last code block wasn't wrapped around ` characters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'd combine &lt;code&gt;sed&lt;/code&gt; with &lt;code&gt;pandoc&lt;/code&gt; to get what I wanted.&lt;/p&gt;
&lt;h2&gt;Preprocessing&lt;/h2&gt;
&lt;p&gt;I replaced the comment identifier &lt;code&gt;%%&lt;/code&gt; with &lt;code&gt;TODO: comment&lt;/code&gt; to the prevent
losing them during conversion. I also replaced code blocks without a language
i.e. &lt;code&gt;{{{&lt;/code&gt; to have bash i.e. &lt;code&gt;{{{bash&lt;/code&gt; and I'd replace this when editting later.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;╰─$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%% save me\nNormal line %% with ending\n{{{&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/\{\{\{$/\{\{\{bash/g&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/%%/TODO: comment/g&amp;#39;&lt;/span&gt;
TODO:&lt;span class="w"&gt; &lt;/span&gt;comment&lt;span class="w"&gt; &lt;/span&gt;save&lt;span class="w"&gt; &lt;/span&gt;me
Normal&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;TODO:&lt;span class="w"&gt; &lt;/span&gt;comment&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;ending
&lt;span class="o"&gt;{{{&lt;/span&gt;bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Post processing&lt;/h2&gt;
&lt;p&gt;I changed the vimwikie-converted linked i.e. &lt;code&gt;[link_to_file](link_to_file
"wikilink")&lt;/code&gt; to use the file name i.e. &lt;code&gt;[link_to_file](link_to_file.md)&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;[link_to_file](link_to_file \&amp;quot;wikilink\&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/(\[.*\])\(([^#]*)((.*) &amp;quot;wikilink&amp;quot;)\)/\1\(\2.md\4\)/g&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I converted all checklists to github's checklist syntax with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;- []{.done4}done\n- []{.done0} not_done&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done[0-3]\}/\[ \] /g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done4\}/\[X\] /g&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and also unquoted all &lt;code&gt;'&lt;/code&gt; characters with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\\&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\\\&amp;#39;/\&amp;#39;/g&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here's the final post processing step:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/(\[.*\])\(([^#]*)((.*) &amp;quot;wikilink&amp;quot;)\)/\1\(\2.md\4\)/g&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\\\&amp;#39;/\&amp;#39;/g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done[0-3]\}/\[ \] /g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done4\}/\[X\] /g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$md_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Putting It All Together&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-euo&lt;span class="w"&gt; &lt;/span&gt;pipefail

&lt;span class="c1"&gt;# files to change extension from to md format&lt;/span&gt;
readarray&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mv_files&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;find&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-iwholename&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*diary/*.wiki&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-or&lt;span class="w"&gt; &lt;/span&gt;-iwholename&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*unorganized_things/*.wiki&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-or&lt;span class="w"&gt; &lt;/span&gt;-iwholename&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*design_docs/*.wiki&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-and&lt;span class="w"&gt; &lt;/span&gt;-not&lt;span class="w"&gt; &lt;/span&gt;-iname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;diary.wiki&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-and&lt;span class="w"&gt; &lt;/span&gt;-not&lt;span class="w"&gt; &lt;/span&gt;-iname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;index.wiki&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-print0&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;mv_files&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;md_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;%%.wiki&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.md&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;mv&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$md_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

readarray&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;files&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;find&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;-name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*.wiki&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-print0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;md_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;%%.wiki&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.md&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/\{\{\{$/\{\{\{bash/g&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/%%/TODO: comment/g&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pandoc&lt;span class="w"&gt; &lt;/span&gt;--from&lt;span class="w"&gt; &lt;/span&gt;vimwiki&lt;span class="w"&gt; &lt;/span&gt;--to&lt;span class="w"&gt; &lt;/span&gt;commonmark_x&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$md_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/(\[.*\])\(([^#]*)((.*) &amp;quot;wikilink&amp;quot;)\)/\1\(\2.md\4\)/g&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\\\&amp;#39;/\&amp;#39;/g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done[0-3]\}/\[ \] /g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done4\}/\[X\] /g&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$md_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Computer"/></entry><entry><title>SC-IM Color Configuration</title><link href="https://blog.jnduli.co.ke/sc-im-color-configuration.html" rel="alternate"/><published>2023-07-01T00:00:00+03:00</published><updated>2023-07-01T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2023-07-01:/sc-im-color-configuration.html</id><summary type="html">&lt;p&gt;I couldn't read cells in &lt;a href="https://github.com/andmarti1424/sc-im"&gt;sc-im&lt;/a&gt; because
there was little contrast between the background and foreground colors. I
temporarily fixed this by changing my terminal's color scheme, but I'd prefer to
keep it. A permanent solution was to change sc-im's colors, for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;color&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;type=INPUT fg=WHITE bg=BLACK …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I couldn't read cells in &lt;a href="https://github.com/andmarti1424/sc-im"&gt;sc-im&lt;/a&gt; because
there was little contrast between the background and foreground colors. I
temporarily fixed this by changing my terminal's color scheme, but I'd prefer to
keep it. A permanent solution was to change sc-im's colors, for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;color&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;type=INPUT fg=WHITE bg=BLACK&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and changed the colors of the help documentation with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type=NORMAL fg=WHITE bg=BLACK&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The help menu provides more details for the colors to use. You type &lt;code&gt;:help&lt;/code&gt; and
search for color with &lt;code&gt;\color&lt;/code&gt;, getting the explanations for all the types
supported. I experimented with a couple of options and saved my final colors in
&lt;code&gt;~/.scimrc&lt;/code&gt;. Here's what I had:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type=INPUT fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type=NORMAL fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type=ERROR_MSG fg=RED bg=BLACK&amp;quot;&lt;/span&gt;
color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type=CELL_SELECTION fg=BLACK bg=WHITE&amp;quot;&lt;/span&gt;
color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type=HEADINGS fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type=WELCOME fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type=MODE fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I also found a ticket on the problem and presented my solution
&lt;a href="https://github.com/andmarti1424/sc-im/issues/297#issuecomment-449555863"&gt;here&lt;/a&gt;.&lt;/p&gt;</content><category term="Computer"/></entry><entry><title>Dev Experience For Personal Projects</title><link href="https://blog.jnduli.co.ke/dev_experience_for_personal_projects.html" rel="alternate"/><published>2023-04-29T00:00:00+03:00</published><updated>2023-04-29T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2023-04-29:/dev_experience_for_personal_projects.html</id><summary type="html">&lt;p&gt;My personal projects have poor developer experience. Any time I want to fix a
bug or improve a service, I experience &lt;a class="reference external" href="https://comics.jnduli.co.ke/pub/looking-at-something-i-set-up-some-years-back/"&gt;a lot of frustration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, I wanted to upgrade the UI of my &lt;a class="reference external" href="https://github.com/jnduli/pomodoro"&gt;pomodoro script&lt;/a&gt; to have colors for completed and
cancelled tasks, better prompts and mark the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;My personal projects have poor developer experience. Any time I want to fix a
bug or improve a service, I experience &lt;a class="reference external" href="https://comics.jnduli.co.ke/pub/looking-at-something-i-set-up-some-years-back/"&gt;a lot of frustration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, I wanted to upgrade the UI of my &lt;a class="reference external" href="https://github.com/jnduli/pomodoro"&gt;pomodoro script&lt;/a&gt; to have colors for completed and
cancelled tasks, better prompts and mark the task status. I couldn't get how the
original script worked and any change I made broke something. I added the
features but the experience was painful. I didn't have another way to tell that
I broke something except from running the script end to end.&lt;/p&gt;
&lt;p&gt;I set up my first server manually, without documentation. There were a lot of
experiments I did, which means it's impossible to create a similar setup in
future or upgrade the same server. A better way would have been to document the
set up, or put everything in code using ansible, with comments that explain
non-obvious configurations.&lt;/p&gt;
&lt;p&gt;I'll try and have at least these in my personal projects to help with dev
experience:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;easy set up of project&lt;/li&gt;
&lt;li&gt;easy and fast testing&lt;/li&gt;
&lt;li&gt;clear documentation on manual and non-obvious steps&lt;/li&gt;
&lt;li&gt;documentation to run and build the project&lt;/li&gt;
&lt;li&gt;documentation on how I deployed the project&lt;/li&gt;
&lt;li&gt;explanation for non-obvious debugging steps&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Computer"/></entry><entry><title>Testing GUIX</title><link href="https://blog.jnduli.co.ke/testing_guix.html" rel="alternate"/><published>2023-03-31T00:00:00+03:00</published><updated>2023-03-31T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2023-03-31:/testing_guix.html</id><summary type="html">&lt;p&gt;I installed guix with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Install nscd (name service cache daemon) to help pick up guix libs&lt;/span&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;nscd
sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nscd

&lt;span class="c1"&gt;# install guix&lt;/span&gt;
&lt;span class="c1"&gt;# Ref: https://guix.gnu.org/manual/en/html_node/Binary-Installation.html&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/tmp
wget&lt;span class="w"&gt; &lt;/span&gt;https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install …&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I installed guix with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Install nscd (name service cache daemon) to help pick up guix libs&lt;/span&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;nscd
sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nscd

&lt;span class="c1"&gt;# install guix&lt;/span&gt;
&lt;span class="c1"&gt;# Ref: https://guix.gnu.org/manual/en/html_node/Binary-Installation.html&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/tmp
wget&lt;span class="w"&gt; &lt;/span&gt;https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
chmod&lt;span class="w"&gt; &lt;/span&gt;+x&lt;span class="w"&gt; &lt;/span&gt;guix-install.sh
sudo&lt;span class="w"&gt; &lt;/span&gt;./guix-install.sh

&lt;span class="c1"&gt;# update guix&lt;/span&gt;
guix&lt;span class="w"&gt; &lt;/span&gt;pull

&lt;span class="c1"&gt;# log out and in again&lt;/span&gt;
&lt;span class="c1"&gt;# confirm guix-daemon is running with:&lt;/span&gt;
ps&lt;span class="w"&gt; &lt;/span&gt;aux&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;guix

&lt;span class="c1"&gt;#  installing guix locales, used by libc installed via guix&lt;/span&gt;
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;glibc-locales

&lt;span class="c1"&gt;# ensures guix libs and apps can do https&lt;/span&gt;
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;nss-certs

&lt;span class="c1"&gt;# Add the following to .profile&lt;/span&gt;
&lt;span class="nv"&gt;GUIX_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.guix-profile&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;GUIX_LOCPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GUIX_PROFILE&lt;/span&gt;/lib/locale
.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$GUIX_PROFILE&lt;/span&gt;&lt;span class="s2"&gt;/etc/profile&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I like i3 window manager and the ubuntu provided version doesn't yet support
gaps. I installed i3 using the ubuntu package manager (apt), which configured
the login manager for i3 in &lt;cite&gt;/usr/share/xsessions/&lt;/cite&gt;. I then installed i3-gaps
using guix and it had preference to the i3 installed via apt.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-install&lt;span class="w"&gt; &lt;/span&gt;i3
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;i3-gaps
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I set up fonts using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;fontconfig
fc-cache&lt;span class="w"&gt; &lt;/span&gt;-rv
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and installed other useful packages:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# installing my editor&lt;/span&gt;
guix&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;neovim&lt;span class="w"&gt; &lt;/span&gt;python-pynvim&lt;span class="w"&gt; &lt;/span&gt;git
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I update my guix system using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;guix&lt;span class="w"&gt; &lt;/span&gt;pull
guix&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="w"&gt; &lt;/span&gt;-u
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I needed to install neovim that was build with a later version of the gcc-tool
chain. I solved this with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;guix&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;neovim&lt;span class="w"&gt; &lt;/span&gt;--with-c-toolchain&lt;span class="o"&gt;=&lt;/span&gt;tree-sitter&lt;span class="o"&gt;=&lt;/span&gt;gcc-tool-chain@12.2
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"/></entry><entry><title>Stack Static Missing Library With Guix</title><link href="https://blog.jnduli.co.ke/stack_static_missing_library_with_guix.html" rel="alternate"/><published>2023-02-25T00:00:00+03:00</published><updated>2023-02-25T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2023-02-25:/stack_static_missing_library_with_guix.html</id><summary type="html">&lt;p&gt;I installed stack_static by downloading the binary &lt;a href="https://github.com/commercialhaskell/stack/releases"&gt;from
github&lt;/a&gt; and moving it to
&lt;code&gt;.local/bin&lt;/code&gt;. I was able to compile haskell programs, but running them failed
with the error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rookie&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="o"&gt;/.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tinfo6&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;48795&lt;/span&gt;&lt;span class="n"&gt;ad824c5ab2c527b42cc08a43bf5cd587c042c536072710c2302b997bb41&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;9.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;exe …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I installed stack_static by downloading the binary &lt;a href="https://github.com/commercialhaskell/stack/releases"&gt;from
github&lt;/a&gt; and moving it to
&lt;code&gt;.local/bin&lt;/code&gt;. I was able to compile haskell programs, but running them failed
with the error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rookie&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="o"&gt;/.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tinfo6&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;48795&lt;/span&gt;&lt;span class="n"&gt;ad824c5ab2c527b42cc08a43bf5cd587c042c536072710c2302b997bb41&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;9.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;libraries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;libgmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;so&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cannot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;No&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;such&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;ldd&lt;/code&gt; showed that the library was missing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;ldd&lt;span class="w"&gt; &lt;/span&gt;.stack-work/install/x86_64-linux-tinfo6/48795ad824c5ab2c527b42cc08a43bf5cd587c042c536072710c2302b997bb41/9.2.5/bin/helloworld-exe
&lt;span class="w"&gt;        &lt;/span&gt;linux-vdso.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007ffd0958e000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libgmp.so.10&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;found
&lt;span class="w"&gt;        &lt;/span&gt;libc.so.6&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libc.so.6&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d530000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libm.so.6&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libm.so.6&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d3ef000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;librt.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/librt.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d3e5000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libdl.so.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libdl.so.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d3e0000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libpthread.so.0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libpthread.so.0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d3be000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libgcc_s.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/4zvswpr2h3b7dvqpvjcdam8vfhyjrmgl-gcc-12.2.0-lib/lib/libgcc_s.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d39d000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/ld-linux-x86-64.so.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/ayc9r7162rphy4zjw8ch01pmyh214h82-glibc-2.33/lib/ld-linux-x86-64.so.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d6f4000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I noticed the search path for most libraries were guix related, so I ran the OS
provided ldd and it found the &lt;code&gt;libgmp.so.10&lt;/code&gt; library.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;/usr/bin/ldd&lt;span class="w"&gt; &lt;/span&gt;.stack-work/install/x86_64-linux-tinfo6/48795ad824c5ab2c527b42cc08a43bf5cd587c042c536072710c2302b997bb41/9.2.5/bin/helloworld-exe
&lt;span class="w"&gt;        &lt;/span&gt;linux-vdso.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007ffc41cc0000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libgmp.so.10&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/lib/x86_64-linux-gnu/libgmp.so.10&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f4148ad2000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libc.so.6&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libc.so.6&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f4148910000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libm.so.6&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libm.so.6&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f41487cf000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;librt.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/librt.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f41487c5000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libdl.so.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libdl.so.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f41487c0000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libpthread.so.0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libpthread.so.0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f414879e000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;libgcc_s.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/gnu/store/4zvswpr2h3b7dvqpvjcdam8vfhyjrmgl-gcc-12.2.0-lib/lib/libgcc_s.so.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f414877d000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;/gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/ld-linux-x86-64.so.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/lib64/ld-linux-x86-64.so.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;0x00007f4148b68000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I didn't know how to add the library to guix (&lt;code&gt;guix install gmp&lt;/code&gt; didn't fix
this). The solution was to compile the program using native OS level utilities.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# opens bash without guix loaded utilities&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;noprofile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;norc&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=$&lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;~/.&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;
&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The binary worked without an errors.&lt;/p&gt;</content><category term="Computer"/></entry><entry><title>Comic Site Migration to SQLite</title><link href="https://blog.jnduli.co.ke/comic_site_migration_to_sqlite.html" rel="alternate"/><published>2023-01-07T00:00:00+03:00</published><updated>2023-01-07T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2023-01-07:/comic_site_migration_to_sqlite.html</id><summary type="html">&lt;p&gt;Postgres was the database for my comic site but I chose to migrate to sqlite
because it would:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;be easier to back up&lt;/li&gt;
&lt;li&gt;use less resources on my server&lt;/li&gt;
&lt;li&gt;be one less service to manage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also don't get a lot of traffic so it wouldn't have an impact.&lt;/p&gt;
&lt;p&gt;The …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Postgres was the database for my comic site but I chose to migrate to sqlite
because it would:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;be easier to back up&lt;/li&gt;
&lt;li&gt;use less resources on my server&lt;/li&gt;
&lt;li&gt;be one less service to manage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also don't get a lot of traffic so it wouldn't have an impact.&lt;/p&gt;
&lt;p&gt;The process followed this general pattern:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;Change the code to use sqlite instead of postgres. I'd maintain the same
paths to the static resources so that I wouldn't have to move these (I stored
static resources on the host).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;Change the docker-compose yml file to:&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Use a different local port for the sqlite instance&lt;/li&gt;
&lt;li&gt;Use a different project name&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Create a json dump from the production server using:
&lt;cite&gt;python manage.py dumpdata --natural-foreign --natural-primary &amp;gt; /var/backups/comic_server/natural_dump.json&lt;/cite&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Change ansible to deploy the project to a different folder and run it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Perform a migration and load the data with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;manage.py&lt;span class="w"&gt; &lt;/span&gt;migrate
python&lt;span class="w"&gt; &lt;/span&gt;manage.py&lt;span class="w"&gt; &lt;/span&gt;loaddata&lt;span class="w"&gt; &lt;/span&gt;/var/backups/comic_server/natural_dump.json
&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Verify the new instance works.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Change nginx configuration to point to the new instance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Turn down the old instance with &lt;cite&gt;docker-compose down&lt;/cite&gt;. I'll clear out the
volumes once I'm sure everything is ok.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note: python commands run in the docker-compose container by first running:
&lt;cite&gt;docker compose exec comic_server /bin/bash&lt;/cite&gt;&lt;/p&gt;
</content><category term="Computer"/></entry><entry><title>Handling Noise in My Head</title><link href="https://blog.jnduli.co.ke/handling_noise_in_my_head.html" rel="alternate"/><published>2022-11-30T00:00:00+03:00</published><updated>2022-11-30T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2022-11-30:/handling_noise_in_my_head.html</id><summary type="html">&lt;p&gt;I complain and anger myself a lot. I'll have an internal dialogue that loops
over the same points, making me feel worse and worse. I'll sometimes write down
why I'm so angry or anxious, and find out my thoughts aren't as important as I
wanted to believe.&lt;/p&gt;
&lt;p&gt;This is &lt;cite&gt;Chatter …&lt;/cite&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I complain and anger myself a lot. I'll have an internal dialogue that loops
over the same points, making me feel worse and worse. I'll sometimes write down
why I'm so angry or anxious, and find out my thoughts aren't as important as I
wanted to believe.&lt;/p&gt;
&lt;p&gt;This is &lt;cite&gt;Chatter&lt;/cite&gt;, where our brain gets stuck in negative thought loops, usually
about a past event e.g. something someone told me (rumination) or about the
future e.g. what will happen (worry).&lt;/p&gt;
&lt;p&gt;I subconsciously like this feeling and sometimes catch myself looking for
something to complain or be angry with. I'll look for someone to validate my
feelings, having a one sided conversations about my problems and complaints. I
won't notice solutions they suggest since I'm too fixated on my problems. Later
on, when I reflect on what they said is when I'll see their solution and angle.&lt;/p&gt;
&lt;p&gt;What seems to work for me is:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;cycling. When I reach some point of exhaustion, I stop thinking and my mind
calms down for the rest of the ride.&lt;/li&gt;
&lt;li&gt;writing. This makes the fuzzy thoughts less so, and I see what the problem is,
rather than feel them.&lt;/li&gt;
&lt;li&gt;smiling: Forcing myself to smile makes me look at my thoughts from a different
angle, and I've found myself laughing at some of the thoughts I had.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other ways I've read that might work are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;distanced self talk, where instead of using I/me while thinking I use my
name or other pronouns like you, he, she.&lt;/li&gt;
&lt;li&gt;practice meditation and mindfulness&lt;/li&gt;
&lt;li&gt;do something else that takes my focus from the rambling thoughts like color
naming, count, recite, run, tidying up, taking a walk.&lt;/li&gt;
&lt;li&gt;Talking/Writing. Thoughts tend to be abstract and unordered and verbalizing
these helps generate meaning from the thoughts.&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;Practice changing my perception:&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last"&gt;
&lt;li&gt;Reframe thoughts (cognitive defusion), for example, &amp;quot;life is meaningless&amp;quot;
becomes &amp;quot;I'm having a thought that life is meaningless&amp;quot;&lt;/li&gt;
&lt;li&gt;Train myself to recognize a negative thought I fall on, and consciously
create a new thought that's based on reality to replace it (Cognitive
Behaviour Therapy).&lt;/li&gt;
&lt;li&gt;Instead of trying to change my internal state, accept it with kindness.
Change internal dialogue to 'Its hard to feel this way but I can get
through this' instead of blaming myself for anxiety.&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://nautil.us/how-to-quiet-your-mind-chatter-238149/"&gt;https://nautil.us/how-to-quiet-your-mind-chatter-238149/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.forbes.com/sites/alicegwalton/2017/02/28/8-science-based-tricks-for-quieting-the-monkey-mind/?sh=59a4f7b81af6"&gt;https://www.forbes.com/sites/alicegwalton/2017/02/28/8-science-based-tricks-for-quieting-the-monkey-mind/?sh=59a4f7b81af6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Random"/></entry><entry><title>How To Code Review</title><link href="https://blog.jnduli.co.ke/how_to_code_review.html" rel="alternate"/><published>2022-10-29T00:00:00+03:00</published><updated>2022-10-29T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2022-10-29:/how_to_code_review.html</id><summary type="html">&lt;p&gt;Code reviews improve the health of a system while spreading ownership of code
and knowledge. A good review process is fast and we can handle low hanging
fruits by automating trivial checks (e.g. running unit tests, style choices) and
choosing style guidelines. We can have high level discussions on …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Code reviews improve the health of a system while spreading ownership of code
and knowledge. A good review process is fast and we can handle low hanging
fruits by automating trivial checks (e.g. running unit tests, style choices) and
choosing style guidelines. We can have high level discussions on the changes
before coding to prevent rewrites.&lt;/p&gt;
&lt;p&gt;Once the changes are ready, the reviewer:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;responds quickly to the review request (if not in the middle of deep work). At
most 1 day shouldn't pass before they respond.&lt;/li&gt;
&lt;li&gt;checks the code and tests for:&lt;ul&gt;
&lt;li&gt;correctness, test coverage, functionality and best practices.&lt;/li&gt;
&lt;li&gt;hard to understand code, unclear names, commented out code, untested code,&lt;/li&gt;
&lt;li&gt;unhandled edge cases, duplication, bad test structure&lt;/li&gt;
&lt;li&gt;too many changes (if these are a lot, ask dev to split the PR).&lt;/li&gt;
&lt;li&gt;comments. They should explain why not what the code is doing (comments !=
documentation).&lt;/li&gt;
&lt;li&gt;consistency&lt;/li&gt;
&lt;li&gt;documentation updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;is kind when commenting on code. They:&lt;ul&gt;
&lt;li&gt;comment on what they like in the PR (positive feedback)&lt;/li&gt;
&lt;li&gt;comment on code and not the coder e.g. instead of &lt;cite&gt;you're creating many db
connections here&lt;/cite&gt; have &lt;cite&gt;this code creates many db connections&lt;/cite&gt;.&lt;/li&gt;
&lt;li&gt;Use questions instead of statements. Questions feel less like criticism and
can trigger creative solutions while also assuming the author knows more
than you do e.g:&lt;ul&gt;
&lt;li&gt;&lt;cite&gt;I find this confusing&lt;/cite&gt; becomes &lt;cite&gt;Could you elaborate on how this works?&lt;/cite&gt;&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;This is unmaintainable&lt;/cite&gt; becomes &lt;cite&gt;What was your vision on maintaining this?&lt;/cite&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use I-messages instead of you-messages i.e. I suggest/think/believe/would,
It's hard for me, For me it seems e.g. &lt;cite&gt;you are writing cryptic code&lt;/cite&gt;
becomes &lt;cite&gt;It's hard for me to grasp what's going on in this code.&lt;/cite&gt;
We see You-messages absolute statements or attacks, and get defensive.&lt;/li&gt;
&lt;li&gt;Use we instead of I/me/you which makes comments less judgemental e.g. &lt;cite&gt;could
we change this function to do it this way?&lt;/cite&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ensures the dev implements explanations in code (i.e. rewrite or a comment).
Explanations in the review tool won't help future devs.&lt;/li&gt;
&lt;li&gt;accepts that there are different solutions and distinguish between common best
practices and personal taste. They are okay with compromises.&lt;/li&gt;
&lt;li&gt;Use the &amp;quot;Yes, and ... &amp;quot; technique to keep an innovative atmosphere. Don't
dismiss fresh and fragile ideas in a draft PR.&lt;/li&gt;
&lt;li&gt;Have discussions in public, and ensure code documents these.&lt;/li&gt;
&lt;li&gt;is explicit about the action they want. Prefix your comments with emojis or
the intent e.g. nit, FYI.&lt;/li&gt;
&lt;li&gt;Reach out to dev if they have too many comments or comments that are too long,
solving misunderstanding early. Talk these out instead of using comments.&lt;/li&gt;
&lt;li&gt;Have a bias for action e.g. approve a PR with minor comments.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.reddit.com/r/ExperiencedDevs/comments/u6fxbm/do_people_think_your_pr_comments_sound_arrogant/"&gt;https://www.reddit.com/r/ExperiencedDevs/comments/u6fxbm/do_people_think_your_pr_comments_sound_arrogant/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.swarmia.com/blog/a-complete-guide-to-code-reviews/"&gt;https://www.swarmia.com/blog/a-complete-guide-to-code-reviews/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://stackoverflow.blog/2019/09/30/how-to-make-good-code-reviews-better/"&gt;https://stackoverflow.blog/2019/09/30/how-to-make-good-code-reviews-better/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://phauer.com/2018/code-review-guidelines/"&gt;https://phauer.com/2018/code-review-guidelines/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://google.github.io/eng-practices/review/reviewer/"&gt;https://google.github.io/eng-practices/review/reviewer/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Computer"/></entry><entry><title>Asking For Help</title><link href="https://blog.jnduli.co.ke/asking_for_help.html" rel="alternate"/><published>2022-08-27T00:00:00+03:00</published><updated>2022-08-27T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2022-08-27:/asking_for_help.html</id><summary type="html">&lt;p&gt;I get and send bad questions. To avoid this, I write my questions in my editor,
review and then copy them to the platform e.g. slack, email. My questions are
better, which makes me wonder if there are other changes that could further
improve my questions.&lt;/p&gt;
&lt;p&gt;A lot of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I get and send bad questions. To avoid this, I write my questions in my editor,
review and then copy them to the platform e.g. slack, email. My questions are
better, which makes me wonder if there are other changes that could further
improve my questions.&lt;/p&gt;
&lt;p&gt;A lot of great resources exist online, and here's a checklist I've made for my
questions.&lt;/p&gt;
&lt;p&gt;Before I consider asking a question, ask:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;What do I want? Avoid thinking that the solution in mind is the problem. I
can tack on the failed solution to the question if need be. This prevents
&lt;a class="reference external" href="https://xyproblem.info/"&gt;the XY problem&lt;/a&gt; when I'm making the question.&lt;/li&gt;
&lt;li&gt;Am I forcing my experience, knowledge or the technology I know to the problem (i.e. &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Einstellung_effect"&gt;einstellung&lt;/a&gt;?&lt;/li&gt;
&lt;li&gt;Spend time making the question before reaching out to someone. This prevents
&lt;a class="reference external" href="https://nohello.net/en/"&gt;sending a hello with no context&lt;/a&gt;, since I have
the question to add after the greeting.&lt;/li&gt;
&lt;li&gt;Do my research, and note down all the findings I've got. This helps when
adding details to the question.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example, I built an image on a server, but failed severally because the
server ran out of memory. I spent a lot of time trying to figure out how to
limit docker memory, but this wasn't the goal. Following the above process could
have helped.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;What did I want? I wanted a custom image on the server.&lt;/li&gt;
&lt;li&gt;Am I forcing the technology I know or the solution I've thought out? Yes I
was. The server ran out of memory severally and I tried to find ways to
limit the memory while building the image. I didn't even stop to consider
that there would be another option to get this image in.&lt;/li&gt;
&lt;li&gt;Spend time making the question before reaching out to someone. At this point
I realized that I was solving the wrong problem, and decided to find other
options for what I wanted.&lt;/li&gt;
&lt;li&gt;Do my research and note down all findings. While researching the original
problem, I found that I can load up a locally build image to a server by
using docker load, which solve the problem, hence no need to ask.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once I've done the above and the problem persists, I make and refine the question by:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Having meaningful subject headers.&lt;/li&gt;
&lt;li&gt;Starting with the goal, then the steps I've taken, hence I ensure others will
know if my steps were wrong or if there were other options I didn't consider.&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;Editing the question to be short but informative. I can include:&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last"&gt;
&lt;li&gt;the environment this occurred (if relevant)&lt;/li&gt;
&lt;li&gt;the symptoms in chronological order&lt;/li&gt;
&lt;li&gt;the research done&lt;/li&gt;
&lt;li&gt;a way to reproduce the error (if possible).&lt;/li&gt;
&lt;li&gt;screenshots if its a UI bug&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;Trimming down code snippets and test cases to the smallest bug-demonstrating version.&lt;/li&gt;
&lt;li&gt;Avoiding open-ended questions by being explicit in what I want. The less
effort my request needs the likelier I'll get a response e.g. 'Can someone
explain X?' forces someone to create a detailed explanation while 'Can
someone provide a pointer to a good explanation of X' means they only send
you to a relevant blog post.&lt;/li&gt;
&lt;li&gt;Writing in clear, grammatical and well spelled language.&lt;/li&gt;
&lt;li&gt;Avoiding yes or no questions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you have the question, then:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Look for a relevant public channel. Avoid private ones or personal messages
since public ones ensure more people see the question and learn from it.&lt;/li&gt;
&lt;li&gt;Follow up with a brief note on the solution to the thread. Upvote helpful
answers and accept any that solved the problem.&lt;/li&gt;
&lt;li&gt;Don't ask questions in ongoing threads since those not following the thread
will not see it.&lt;/li&gt;
&lt;li&gt;Be courteous, use please and 'thanks for your attention', etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.catb.org/esr/faqs/smart-questions.html"&gt;http://www.catb.org/esr/faqs/smart-questions.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Einstellung_effect"&gt;https://en.wikipedia.org/wiki/Einstellung_effect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://xyproblem.info/"&gt;https://xyproblem.info/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://nohello.net/en/"&gt;https://nohello.net/en/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Random"/></entry><entry><title>My Firefox Configuration</title><link href="https://blog.jnduli.co.ke/my_firefox_configuration.html" rel="alternate"/><published>2022-07-02T00:00:00+03:00</published><updated>2022-07-02T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2022-07-02:/my_firefox_configuration.html</id><summary type="html">&lt;p&gt;I like firefox, and I've tweaked it to be ideal for me. The extensions I have
are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/darkreader/"&gt;Dark reader&lt;/a&gt;: I
prefer dark themes, so this applies one to websites. This works great except
for my bank's website, which I've excluded in the plugin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/tridactyl-vim/"&gt;Tridactyl&lt;/a&gt;:
provides vim keybindings. It's intuitive and …&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;I like firefox, and I've tweaked it to be ideal for me. The extensions I have
are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/darkreader/"&gt;Dark reader&lt;/a&gt;: I
prefer dark themes, so this applies one to websites. This works great except
for my bank's website, which I've excluded in the plugin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/tridactyl-vim/"&gt;Tridactyl&lt;/a&gt;:
provides vim keybindings. It's intuitive and I'm fond of how it implemented
bookmarks. I changed the theme to shydactyl-dark using:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;colors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--url https://raw.githubusercontent.com/eeshugerman/shydactyl-variations/master/dist/shydactyl-dark.css shydactyl-dark&lt;/span&gt;
&lt;span class="nv"&gt;colourscheme&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;shydactyl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;dark&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;When opening a new tab, there'd be a white canvas that immediately
switched to dark-mode, a flash bang, which was disorienting. I found a solution on &lt;a class="reference external" href="https://github.com/tridactyl/tridactyl/issues/2510#issuecomment-763198138I"&gt;this github comment&lt;/a&gt;
and applied it by opening &lt;cite&gt;$HOME/.mozilla/firefox/profile-dir/chrome/userContent.css&lt;/cite&gt; and adding:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;   dark background in new tabs without a white flash (with tridactyl newtab)&lt;/span&gt;
&lt;span class="c"&gt;   @see: https://github.com/tridactyl/tridactyl/issues/2510&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;--tridactyl-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#1d1b19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;--tridactyl-fg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;white&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;    set the background color of the new tab page (without tridactyl or with tridactyl without newtab)&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;-moz-document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;url-prefix&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;about&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;home&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;url-prefix&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;about&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;newtab&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#1d1b19&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/"&gt;uBlock origin&lt;/a&gt;: ad blocker&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/leechblock-ng/"&gt;Leechblock NG&lt;/a&gt;: blocks
sites that I don't want to visit. I have to add these sites to a block list though,
but once done, it's difficult to open them. I've added youtube, twitter and
more, and this helps me concentrate on important tasks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/remove-youtube-s-suggestions/"&gt;Remove youtube suggestions&lt;/a&gt;:
blocks distracting features on youtube. I've removed the &lt;cite&gt;Explore link&lt;/cite&gt;,
&lt;cite&gt;Shorts link&lt;/cite&gt; and &lt;cite&gt;End of Video suggestions&lt;/cite&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/tab-counter-webext/"&gt;Tab Counter&lt;/a&gt;: shows
how many windows and tabs I have open, and the number of tabs in the current
window. This gives me a rough idea of whether my tabs are becoming
unmanageable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/sponsorblock/"&gt;SponsorBlock&lt;/a&gt;: skips
sponsor sections in youtube videos.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also change the following configs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;clipboardevents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;False&lt;/span&gt;
&lt;span class="nv"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;css&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;devPixelsPerPx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.25&lt;/span&gt;
&lt;span class="nv"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;systemUsesDarkTheme&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nv"&gt;toolkit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;legacyUserProfileCustomizations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;stylesheets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nv"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;background_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;000000&lt;/span&gt;
&lt;span class="nv"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;foreground_color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;ffffff&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I previously had a problem where the first menu item on right click would be
chosen in firefox. I haven't experienced this in a while, but here's a
solution just in case: &lt;a class="reference external" href="https://wiki.archlinux.org/title/Firefox#Right_mouse_button_instantly_clicks_the_first_option_in_window_managers"&gt;soln for mouse clicking&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"/></entry><entry><title>My Opinions on expenses</title><link href="https://blog.jnduli.co.ke/my_opinions_on_expenses.html" rel="alternate"/><published>2022-06-04T00:00:00+03:00</published><updated>2022-06-04T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2022-06-04:/my_opinions_on_expenses.html</id><summary type="html">&lt;div class="section" id="cheap-items"&gt;
&lt;h2&gt;Cheap items&lt;/h2&gt;
&lt;p&gt;I read &lt;a class="reference external" href="https://www.johndcook.com/blog/2020/07/25/worst-tool-for-the-job/"&gt;this article about buying the cheapest tool first&lt;/a&gt;, and if I
use it until it breaks, then I can buy the most expensive one. I've tried to
apply this to my purchases, and I've realized that I am sometimes okay with the
cheap things I've bought …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="cheap-items"&gt;
&lt;h2&gt;Cheap items&lt;/h2&gt;
&lt;p&gt;I read &lt;a class="reference external" href="https://www.johndcook.com/blog/2020/07/25/worst-tool-for-the-job/"&gt;this article about buying the cheapest tool first&lt;/a&gt;, and if I
use it until it breaks, then I can buy the most expensive one. I've tried to
apply this to my purchases, and I've realized that I am sometimes okay with the
cheap things I've bought&lt;/p&gt;
&lt;p&gt;For example, I wanted a laptop, and saved up Ksh 150K for it, but chose to try
out an older thinkpad model first. I bought a refurbished thinkpad t440 for Ksh
30K and I love it. It has most of the things I need and great linux support. The
only gotcha is playing AAA games, but this led me to trying out niche games and
I've found some hidden gems. If this laptop ever breaks, I'll get a similar one.
I don't see the point of spending 5 times the amount on something that is
marginally better (for my needs that is).&lt;/p&gt;
&lt;p&gt;Sometimes the most expensive item is difficult to maintain, especially when
parts need to be replaced. When we moved into our home, we bought the most
expensive shower head our electrician recommended, and it worked for a year
before the heating element broke. The electrician tried to find a replacement,
but couldn't, so we bought a new shower head. But this time we got the lower
priced ones that are more common. This also happened with my brother's laptop
(an ultrabook), where he'd accidentally poured water on the keyboard, and it
needed to be replaced. It took weeks to find a replacement, and it was costly.&lt;/p&gt;
&lt;p&gt;I now purchase cheap items mostly because:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;It provides a chance to see if I need it or not.&lt;/li&gt;
&lt;li&gt;The cheap item are sometimes capable of what I need.&lt;/li&gt;
&lt;li&gt;The cheap items are sometimes easier to repair.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I avoid cheap items that have too many features for the price though e.g. a
convertible laptop, with a touch screen, support for a digital pen, light weight
and more. At that price point, these features don't make sense and there are
some shortcuts made e.g. poor build quality.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="impulse-purchases"&gt;
&lt;h2&gt;Impulse purchases&lt;/h2&gt;
&lt;p&gt;I sometimes get an urge to buy something I've seen, because seeing causes my
brain to find uses for it. For example, I'll see a camera and start imagining
all the cool photos I can take, while ignoring that I rarely take pictures on my
smart phone. Being aware of this helps a bit, especially when it comes to places
I avoid (ref: atomic habits).&lt;/p&gt;
&lt;p&gt;Supermarkets and malls may be designed with this in mind. In malls, I easily get
lost when looking for a particular shop, meaning that I see a lot more things
that triggers the impulse. I try to avoid malls and look for alternatives. When
shopping, I make a list and stick to it, avoiding cues from the supermarket.&lt;/p&gt;
&lt;p&gt;I use leetblock and adblockers on my computers to block websites that provide
these cues. This makes it really hard to visit them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="experiences-vs-things"&gt;
&lt;h2&gt;Experiences vs Things&lt;/h2&gt;
&lt;p&gt;I also liked &lt;a class="reference external" href="https://write.as/harold-lee/theres-a-phrase-going-around-that-you-should-buy-experiences-not-things"&gt;this article on buying things not experiences&lt;/a&gt;,
and learnt that there's a blurry boundary between items and experiences, in that
there are experience like things e.g. owning a workshop, and there are
thing-like experiences e.g. an instagrammable vacation. Experiences are
preferred because of limits in our lives e.g. we don't have enough space for
them, or it could be a way to show that we're better in a world of material
abundance, hence the 'buy experiences not things' mantra.&lt;/p&gt;
&lt;p&gt;This ignores that we can get things that can provide multiple life changing
experiences over the course of their ownership, so long as they're carefully
chosen. A naive example would be to purchase a gaming rig rather than making
payments at a gaming shop. This provides multiple chances to explore games you
enjoy, playing with friends and even meeting random people online. Another
similar example provided is owning a large living room, which provides a change
to host friends and expand your network.&lt;/p&gt;
&lt;p&gt;So where possible, consider the experiences of making a purchase, rather than
just brushing it off as materialism. This though means I should also be aware of
the biases mentioned in the previous section, and I try to balance both of
these.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Random"/></entry><entry><title>Moving home directory to another partition</title><link href="https://blog.jnduli.co.ke/moving_home_directory_to_another_partition.html" rel="alternate"/><published>2022-04-30T00:00:00+03:00</published><updated>2022-04-30T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2022-04-30:/moving_home_directory_to_another_partition.html</id><summary type="html">&lt;p&gt;I'd need to set up ubuntu, but I didn't want to lose my home directory.
Everything was in one partition, so I'd lose my home folder with a re-install. I
didn't want this, so I moved it into another partition.&lt;/p&gt;
&lt;p&gt;The new partition would be the size of my home …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'd need to set up ubuntu, but I didn't want to lose my home directory.
Everything was in one partition, so I'd lose my home folder with a re-install. I
didn't want this, so I moved it into another partition.&lt;/p&gt;
&lt;p&gt;The new partition would be the size of my home folder at least, and I
found this by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/home
du&lt;span class="w"&gt; &lt;/span&gt;-sch&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I didn't have enough space, so I cleared up some space using &lt;a class="reference external" href="https://blog.jnduli.co.ke/freeing-up-space-in-linux-machine.html"&gt;these instructions&lt;/a&gt;. I made sure the free
space was equal to m home directory + 50GB. I don't want to be unable to store
new files.&lt;/p&gt;
&lt;p&gt;I resized (shrunk) the current partition, then created the new partition from
the unallocated space. I used &lt;a class="reference external" href="https://gparted.org/livecd.php"&gt;gparted live usb&lt;/a&gt; for this. It's easy to use the GUI tool to
shrink and create new partitions.&lt;/p&gt;
&lt;p&gt;Once done, I logged into my original OS as the root user, mounted the new
partition and copied over my home folder with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;/dev/sdc2&lt;span class="w"&gt; &lt;/span&gt;/mnt
cp&lt;span class="w"&gt; &lt;/span&gt;-rp&lt;span class="w"&gt; &lt;/span&gt;/home/*&lt;span class="w"&gt; &lt;/span&gt;/mnt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# cp -r --preserve=all /home/* /mnt might be better&lt;/span&gt;
mv&lt;span class="w"&gt; &lt;/span&gt;/home&lt;span class="w"&gt; &lt;/span&gt;/home.old
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I got the uuid for the new partition with &lt;cite&gt;blkid&lt;/cite&gt;, and modified my &lt;cite&gt;/etc/fstab&lt;/cite&gt;
to automatically mount this partition on boot as my home directory with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# home directory mount&lt;/span&gt;
&lt;span class="nv"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;uuid_from_blkid_output&lt;span class="w"&gt;         &lt;/span&gt;/home&lt;span class="w"&gt;           &lt;/span&gt;ext4&lt;span class="w"&gt;            &lt;/span&gt;rw,relatime&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I rebooted my laptop and everything seemed ok.&lt;/p&gt;
&lt;p&gt;Lastly, I cleaned out the &lt;cite&gt;home.old&lt;/cite&gt; folder with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;/home.old
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now I could safely change my OS without losing my home directory.&lt;/p&gt;
</content><category term="Computer"/></entry><entry><title>Kubernetes Basics</title><link href="https://blog.jnduli.co.ke/kubernetes_basics.html" rel="alternate"/><published>2022-02-26T00:00:00+03:00</published><updated>2022-02-26T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2022-02-26:/kubernetes_basics.html</id><summary type="html">&lt;p&gt;&amp;quot;We've got this project on kubernetes that you'll be helping maintain&amp;quot;&lt;/p&gt;
&lt;p&gt;This started my journey with kubernetes. I found a great tutorial from
&lt;a class="reference external" href="https://www.freecodecamp.org/news/the-kubernetes-handbook/"&gt;freecodecamp&lt;/a&gt; and this
blog is an attempt to set up some personal projects using it. It's best
to read the original though as it's more in-depth.&lt;/p&gt;
&lt;p&gt;I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&amp;quot;We've got this project on kubernetes that you'll be helping maintain&amp;quot;&lt;/p&gt;
&lt;p&gt;This started my journey with kubernetes. I found a great tutorial from
&lt;a class="reference external" href="https://www.freecodecamp.org/news/the-kubernetes-handbook/"&gt;freecodecamp&lt;/a&gt; and this
blog is an attempt to set up some personal projects using it. It's best
to read the original though as it's more in-depth.&lt;/p&gt;
&lt;p&gt;I wanted to serve an &lt;cite&gt;index.html&lt;/cite&gt; for a first project. A &lt;a class="reference external" href="https://kubernetes.io/docs/concepts/workloads/pods/#working-with-pods"&gt;pod&lt;/a&gt;
would be used. A pod is the smallest deployable unit in kubernetes, and
it can contain one or more containers (e.g. docker containers). Its an
isolated environment to run a docker image, providing storage and
networking.&lt;/p&gt;
&lt;p&gt;To create a pod, I can create one manually or use a &lt;a class="reference external" href="https://kubernetes.io/docs/concepts/workloads/pods/#pods-and-controllers"&gt;workload resource&lt;/a&gt;,
which provide extra features like replication, recreating pods when one
stops working and more. The workload resources have a pod template,
which provides a description of how to create the pods we want.&lt;/p&gt;
&lt;p&gt;A &lt;a class="reference external" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/"&gt;deployment&lt;/a&gt;
is a workload resource that creates replicas of the pod. I wanted 3 pods
serving the &lt;cite&gt;index.html&lt;/cite&gt; file, so I'd use a deployment.&lt;/p&gt;
&lt;p&gt;To start off, I installed packages to help me play with kubernetes
locally:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;minikube&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;docker
sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;docker
minikube&lt;span class="w"&gt; &lt;/span&gt;config&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;driver&lt;span class="w"&gt; &lt;/span&gt;docker
minikube&lt;span class="w"&gt; &lt;/span&gt;start
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I also created a dockerfile that served the &lt;cite&gt;index.html&lt;/cite&gt; file using
nginx.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;# tagged static:0.1.0&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nginx:1.21.1&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;index.html&lt;span class="w"&gt; &lt;/span&gt;/usr/share/nginx/html/index.html
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I created a yml file that defined the deployment resource that would be
created in minikube.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# static_deployment.yml&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;apps/v1&lt;/span&gt;
&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;Deployment&lt;/span&gt;
&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;static-website-deployment&lt;/span&gt;
&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;3&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;matchLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;static-website-pod&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;static-website-pod&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# pod template section&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;static-website-container&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;static:0.1.0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containerPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;80&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This creates a deployment work resource with the name
&lt;cite&gt;static-website-deployment&lt;/cite&gt;. The deployment ensures that there are 3
pods running the docker image at any one time (defined in replicas). The
selector.matchLabels.app is used to define what pods are being managed,
and are the same as the metadata.labels.app found in the template
section. This metadata is applied to each pod that is created. The pod
template defines how the pod are created, so in each of the 3 pods there
will be a running container named static-website-container, and the pod
would expose port 80.&lt;/p&gt;
&lt;p&gt;To run the above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;minikube&lt;span class="w"&gt; &lt;/span&gt;start
&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;minikube&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;minikube&lt;span class="w"&gt; &lt;/span&gt;docker-env&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# ensure docker images are built in minikube context&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;static:0.1.0&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;Dockerfile_static_content&lt;span class="w"&gt; &lt;/span&gt;.
kubectl&lt;span class="w"&gt; &lt;/span&gt;apply&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;k8s/deployment.yml
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To check that things are running as expected:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;╰─$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;deployment
NAME&lt;span class="w"&gt;                        &lt;/span&gt;READY&lt;span class="w"&gt;   &lt;/span&gt;UP-TO-DATE&lt;span class="w"&gt;   &lt;/span&gt;AVAILABLE&lt;span class="w"&gt;   &lt;/span&gt;AGE
static-website-deployment&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;/3&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;17s
╰─$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;pods
NAME&lt;span class="w"&gt;                                         &lt;/span&gt;READY&lt;span class="w"&gt;   &lt;/span&gt;STATUS&lt;span class="w"&gt;    &lt;/span&gt;RESTARTS&lt;span class="w"&gt;   &lt;/span&gt;AGE
static-website-deployment-57bdbf7d94-7ngwt&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;/1&lt;span class="w"&gt;     &lt;/span&gt;Running&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;4s
static-website-deployment-57bdbf7d94-9l5cv&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;/1&lt;span class="w"&gt;     &lt;/span&gt;Running&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;4s
static-website-deployment-57bdbf7d94-gj59k&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;/1&lt;span class="w"&gt;     &lt;/span&gt;Running&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;4s
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I wanted to use curl to verify the pods are running correctly, but the
kubernetes environment is isolated. To deal with this, kubernetes has
&lt;a class="reference external" href="https://kubernetes.io/docs/concepts/services-networking/service/"&gt;services&lt;/a&gt;
which provide a means of exposing a set of pods. I set up a
&lt;cite&gt;LoadBalancer&lt;/cite&gt; service, which provides an ip address and a port that can
be used to access the pods.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# static_load_balancer.yml
apiVersion: v1
kind: Service
metadata:
  name: static-load-balancer
spec:
  selector:
    app: static-website-pod
  ports:
    - port: 80
      targetPort: 80
  type: LoadBalancer
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and ran the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;╰─$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;apply&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;static_load_balancer.yml
service/static-load-balancer&lt;span class="w"&gt; &lt;/span&gt;unchanged
╰─$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;services
NAME&lt;span class="w"&gt;                   &lt;/span&gt;TYPE&lt;span class="w"&gt;           &lt;/span&gt;CLUSTER-IP&lt;span class="w"&gt;      &lt;/span&gt;EXTERNAL-IP&lt;span class="w"&gt;   &lt;/span&gt;PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;AGE
kubernetes&lt;span class="w"&gt;             &lt;/span&gt;ClusterIP&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.96.0.1&lt;span class="w"&gt;       &lt;/span&gt;&amp;lt;none&amp;gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;443&lt;/span&gt;/TCP&lt;span class="w"&gt;        &lt;/span&gt;6d5h
static-load-balancer&lt;span class="w"&gt;   &lt;/span&gt;LoadBalancer&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.105.222.19&lt;span class="w"&gt;   &lt;/span&gt;&amp;lt;pending&amp;gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;:30133/TCP&lt;span class="w"&gt;   &lt;/span&gt;116s
╰─$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;minikube&lt;span class="w"&gt; &lt;/span&gt;ip&lt;span class="k"&gt;)&lt;/span&gt;:30133
&amp;lt;!DOCTYPE&lt;span class="w"&gt; &lt;/span&gt;html&amp;gt;
&amp;lt;html&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;en&amp;quot;&lt;/span&gt;&amp;gt;
&lt;span class="w"&gt;    &lt;/span&gt;&amp;lt;head&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;cite&gt;minikube ip&lt;/cite&gt; provides the ip address of minikube, and the port is the
second part of the PORTS section of the static-load-balancer service.&lt;/p&gt;
&lt;p&gt;Since what we're exposing is http traffic, I could also use an &lt;a class="reference external" href="https://kubernetes.io/docs/concepts/services-networking/ingress/"&gt;ingress
object&lt;/a&gt;,
which is a type of controller that can expose http and https traffic.
Other advantages include ssl termination and name-based virtual
hosting. I first needed to enable ingress in minikube with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;minikube&lt;span class="w"&gt; &lt;/span&gt;addons&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ingress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The ingress controller links up with a service, so we could use the
LoadBalancer service previously created.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: static-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: static-load-balancer
                port:
                  number: 80
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, it doesn't make much sense to have both an ingress object and a
load balancer pointing to the same thing. Another service I could use
is the &lt;cite&gt;ClusterIP&lt;/cite&gt; which provides an ip internal to the cluster. This
way we only have one entry point into minikube.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# static_ingress.yml
---
apiVersion: v1
kind: Service
metadata:
  name: static-clusterip
spec:
  selector:
    app: static-website-pod
  ports:
    - port: 80
      targetPort: 80
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: static-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: static-clusterip
                port:
                  number: 80
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;╰─$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;services
NAME&lt;span class="w"&gt;                   &lt;/span&gt;TYPE&lt;span class="w"&gt;           &lt;/span&gt;CLUSTER-IP&lt;span class="w"&gt;      &lt;/span&gt;EXTERNAL-IP&lt;span class="w"&gt;   &lt;/span&gt;PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;AGE
kubernetes&lt;span class="w"&gt;             &lt;/span&gt;ClusterIP&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.96.0.1&lt;span class="w"&gt;       &lt;/span&gt;&amp;lt;none&amp;gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;443&lt;/span&gt;/TCP&lt;span class="w"&gt;        &lt;/span&gt;6d6h
static-clusterip&lt;span class="w"&gt;       &lt;/span&gt;ClusterIP&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.109.227.9&lt;span class="w"&gt;    &lt;/span&gt;&amp;lt;none&amp;gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;/TCP&lt;span class="w"&gt;         &lt;/span&gt;108s
static-load-balancer&lt;span class="w"&gt;   &lt;/span&gt;LoadBalancer&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.105.222.19&lt;span class="w"&gt;   &lt;/span&gt;&amp;lt;pending&amp;gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;:30133/TCP&lt;span class="w"&gt;   &lt;/span&gt;81m
╰─$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;ingress
NAME&lt;span class="w"&gt;             &lt;/span&gt;CLASS&lt;span class="w"&gt;    &lt;/span&gt;HOSTS&lt;span class="w"&gt;   &lt;/span&gt;ADDRESS&lt;span class="w"&gt;     &lt;/span&gt;PORTS&lt;span class="w"&gt;   &lt;/span&gt;AGE
static-ingress&lt;span class="w"&gt;   &lt;/span&gt;&amp;lt;none&amp;gt;&lt;span class="w"&gt;   &lt;/span&gt;*&lt;span class="w"&gt;       &lt;/span&gt;localhost&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;25m
╰─$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;minikube&lt;span class="w"&gt; &lt;/span&gt;ip&lt;span class="k"&gt;)&lt;/span&gt;
&amp;lt;!DOCTYPE&lt;span class="w"&gt; &lt;/span&gt;html&amp;gt;
&amp;lt;html&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;en&amp;quot;&lt;/span&gt;&amp;gt;
&lt;span class="w"&gt;    &lt;/span&gt;&amp;lt;head&amp;gt;
&lt;span class="w"&gt;    &lt;/span&gt;.
&lt;span class="w"&gt;    &lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Having the basics of kubernetes i.e. controllers, services and ingress
down, I tried to set up a django project. I'll add a link to this when
it's ready.&lt;/p&gt;
</content><category term="Computer"/></entry><entry><title>Sending Mail from Cron in Ubuntu 20.04 LTS</title><link href="https://blog.jnduli.co.ke/sending_mail_from_cron_in_ubuntu_20_04_lts.html" rel="alternate"/><published>2022-01-15T00:00:00+03:00</published><updated>2022-01-15T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2022-01-15:/sending_mail_from_cron_in_ubuntu_20_04_lts.html</id><summary type="html">&lt;p&gt;I created a cronjob to back up my server content and wanted to test out
emailing of errors when they occurred. To set this up, I installed
&lt;cite&gt;msmtp&lt;/cite&gt; and &lt;cite&gt;msmtp-mta&lt;/cite&gt; to help send emails using an smtp server and
&lt;cite&gt;bsd-mailx&lt;/cite&gt; to test sending emails from terminal. The cronjob entry was …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I created a cronjob to back up my server content and wanted to test out
emailing of errors when they occurred. To set this up, I installed
&lt;cite&gt;msmtp&lt;/cite&gt; and &lt;cite&gt;msmtp-mta&lt;/cite&gt; to help send emails using an smtp server and
&lt;cite&gt;bsd-mailx&lt;/cite&gt; to test sending emails from terminal. The cronjob entry was:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;MAILTO=&amp;quot;email@example.org&amp;quot;
*/1 * * * * echo &amp;quot;using default crontab mail functionality variable&amp;quot;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, I got the following errors (check out &lt;cite&gt;/var/log/syslog&lt;/cite&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Dec&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;06&lt;/span&gt;:14:02&lt;span class="w"&gt; &lt;/span&gt;ubuntu-docker-comic-misc-server&lt;span class="w"&gt; &lt;/span&gt;cron&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;7901&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;sendmail:&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;server&lt;span class="w"&gt; &lt;/span&gt;did&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;accept&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;mail
Dec&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;06&lt;/span&gt;:14:02&lt;span class="w"&gt; &lt;/span&gt;ubuntu-docker-comic-misc-server&lt;span class="w"&gt; &lt;/span&gt;cron&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;7901&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;sendmail:&lt;span class="w"&gt; &lt;/span&gt;server&lt;span class="w"&gt; &lt;/span&gt;message:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;551&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;.7.1&lt;span class="w"&gt; &lt;/span&gt;Not&lt;span class="w"&gt; &lt;/span&gt;authorised&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;send&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;header&lt;span class="w"&gt; &lt;/span&gt;address
Dec&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;06&lt;/span&gt;:14:02&lt;span class="w"&gt; &lt;/span&gt;ubuntu-docker-comic-misc-server&lt;span class="w"&gt; &lt;/span&gt;cron&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;7901&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;sendmail:&lt;span class="w"&gt; &lt;/span&gt;could&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;send&lt;span class="w"&gt; &lt;/span&gt;mail&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;account&lt;span class="w"&gt; &lt;/span&gt;default&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;/home/rookie/.config/msmtp/config&lt;span class="o"&gt;)&lt;/span&gt;
Dec&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;06&lt;/span&gt;:14:02&lt;span class="w"&gt; &lt;/span&gt;ubuntu-docker-comic-misc-server&lt;span class="w"&gt; &lt;/span&gt;CRON&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;7899&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;rookie&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MAIL&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mailed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;but&lt;span class="w"&gt; &lt;/span&gt;got&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;0x0045&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;MTA#012&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which confused me since msmtp should have had the from field set. Here's
the config:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# Set default values for all following accounts.
defaults
tls            on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
auth           on
logfile        ~/.msmtp.log

account fastmail
host smtp.fastmail.com
port 465
from email@replace_me.com
user replace_me@fastmail.com
password some_password
tls_starttls off

# Set a default account
account default : fastmail
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and msmtp logs showed that the appropriate from address was being used.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Dec&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;06&lt;/span&gt;:15:02&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;smtp.fastmail.com&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;tls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;replace_me@fastmail.com&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;email@replace_me.com&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;recipients&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;email@example.org&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;smtpstatus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;551&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;smtpmsg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;551 5.7.1 Not authorised to send from this header address&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;errormsg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;the server did not accept the mail&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;exitcode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;EX_UNAVAILABLE
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I had made an incorrect assumption. I read msmtp docs and found that the
&lt;cite&gt;set from = someemail&lt;/cite&gt; configuration is used only when the original
email is lacking the from field. A later release would support
&lt;cite&gt;set_from_header on&lt;/cite&gt; flag that would replace the from field with the
config value. The version I was on is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rookie@ubuntu-docker-comic-misc-server:~$&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;policy&lt;span class="w"&gt; &lt;/span&gt;msmtp
msmtp:
&lt;span class="w"&gt;  &lt;/span&gt;Installed:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.8.6-1
&lt;span class="w"&gt;  &lt;/span&gt;Candidate:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.8.6-1
&lt;span class="w"&gt;  &lt;/span&gt;Version&lt;span class="w"&gt; &lt;/span&gt;table:
&lt;span class="w"&gt; &lt;/span&gt;***&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.8.6-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://mirrors.digitalocean.com/ubuntu&lt;span class="w"&gt; &lt;/span&gt;focal/universe&lt;span class="w"&gt; &lt;/span&gt;amd64&lt;span class="w"&gt; &lt;/span&gt;Packages
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/var/lib/dpkg/status
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next option was to find out if ubuntu's cron has support for setting a
custom from address. Ubuntu uses a patched &lt;cite&gt;vixie-cron&lt;/cite&gt;, but looking
through the source code &lt;a class="reference external" href="https://github.com/vixie/cron/blob/690fc534c7316e2cf6ff16b8e83ba7734b5186d2/do_command.c#L432"&gt;on vixie-cron's github page&lt;/a&gt;,
the from field was either set up to the cron user or root.&lt;/p&gt;
&lt;p&gt;There was a future patched version from ubuntu that provided support for
a &lt;cite&gt;MAILFROM&lt;/cite&gt; field, found in this &lt;a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/cron/+bug/1750051"&gt;bug discussion&lt;/a&gt;, but
this was not available yet in my ubuntu release.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rookie@ubuntu-docker-comic-misc-server:~$&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;policy&lt;span class="w"&gt; &lt;/span&gt;cron
cron:
&lt;span class="w"&gt;  &lt;/span&gt;Installed:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.0pl1-136ubuntu1
&lt;span class="w"&gt;  &lt;/span&gt;Candidate:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.0pl1-136ubuntu1
&lt;span class="w"&gt;  &lt;/span&gt;Version&lt;span class="w"&gt; &lt;/span&gt;table:
&lt;span class="w"&gt; &lt;/span&gt;***&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.0pl1-136ubuntu1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://mirrors.digitalocean.com/ubuntu&lt;span class="w"&gt; &lt;/span&gt;focal/main&lt;span class="w"&gt; &lt;/span&gt;amd64&lt;span class="w"&gt; &lt;/span&gt;Packages
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/var/lib/dpkg/status
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The fix I chose was to pipe the output to the mail command.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;*/1 * * * * (echo &amp;quot;normal output&amp;quot; &amp;amp;&amp;amp; cat asdfsfd) 2&amp;gt;&amp;amp;1 | mail -s &amp;quot;test&amp;quot; $MAILTO
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This works because the mail command doesn't have a from field, so msmtp
will set it from the config. I also pipe stderr to stdout so that it's
also passed to the mail command. Only failing with this method is that
if the cron job doesn't output anything, I'll still get a blank email. I
don't have a problem with this though since the final cron job runs
weekly.&lt;/p&gt;
&lt;p&gt;I'll also be on the look out for when the updated versions of msmtp or
vixie-cron are out and update my jobs.&lt;/p&gt;
&lt;p&gt;Here's a great resource for things you should do when setting up
&lt;a class="reference external" href="https://blog.sanctum.geek.nz/cron-best-practices/"&gt;cronjobs&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"/></entry><entry><title>Static Website with Pandoc</title><link href="https://blog.jnduli.co.ke/static_website_with_pandoc.html" rel="alternate"/><published>2021-07-31T00:00:00+03:00</published><updated>2021-07-31T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2021-07-31:/static_website_with_pandoc.html</id><summary type="html">&lt;p&gt;I needed to pull off a quick website that would have various mathematics
questions, and thought to try and use pandoc. Here are my learnings:&lt;/p&gt;
&lt;p&gt;I first installed &lt;cite&gt;pandoc-bin&lt;/cite&gt; because I didn't to deal with a lot of
haskell dependencies.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;yay&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;pandoc-bin
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first iteration I made generated an …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I needed to pull off a quick website that would have various mathematics
questions, and thought to try and use pandoc. Here are my learnings:&lt;/p&gt;
&lt;p&gt;I first installed &lt;cite&gt;pandoc-bin&lt;/cite&gt; because I didn't to deal with a lot of
haskell dependencies.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;yay&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;pandoc-bin
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first iteration I made generated an &lt;cite&gt;index.html&lt;/cite&gt; file with
all the contents and a table of contents. The following bashscript shows
this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;output
pandoc&lt;span class="w"&gt; &lt;/span&gt;--toc&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;markdown&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;html&lt;span class="w"&gt; &lt;/span&gt;--mathjax&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;./output/index.html&lt;span class="w"&gt; &lt;/span&gt;*.md
rsync&lt;span class="w"&gt; &lt;/span&gt;-rav&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ssh -p PORT&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;output/&lt;span class="w"&gt; &lt;/span&gt;username@domain:/destination_folder
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A sample file would look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gh"&gt;# Title that will be in table of contents&lt;/span&gt;

Content body
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The order in the table of contents is on the alphabetical ordering of
the files. In my case, the date prefixed all files, so they ended up in
the order I wanted them to.&lt;/p&gt;
&lt;p&gt;The file however became too large after some time. I didn't want to get
a static site manager for this, so I tweaked the bashscript.&lt;/p&gt;
&lt;p&gt;I can compile each file to a separate html file with pandoc, but I first
need to get a list of all files I want.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;find&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;-maxdepth&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-type&lt;span class="w"&gt; &lt;/span&gt;f&lt;span class="w"&gt; &lt;/span&gt;-name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*.md&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-printf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%f\n&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sort&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xargs&lt;span class="w"&gt; &lt;/span&gt;-I&lt;span class="w"&gt; &lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;pandoc&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;markdown&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;html&lt;span class="w"&gt; &lt;/span&gt;--mathjax&lt;span class="w"&gt; &lt;/span&gt;--metadata&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;questions&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;%.html&lt;span class="w"&gt;  &lt;/span&gt;%
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I need to ensure compile the files to a common directory so that its
easy to sync with my server. An index file that links up to all the
children files should also be generated dynamically, so that I can
easily find the links. I created a custom function &lt;cite&gt;gen_html&lt;/cite&gt; that does
this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;gen_html&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;test_compile
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;file_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;[&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;](./&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.html)&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;index.md
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;index.md
&lt;span class="w"&gt;    &lt;/span&gt;pandoc&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;markdown&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;html&lt;span class="w"&gt; &lt;/span&gt;--mathjax&lt;span class="w"&gt; &lt;/span&gt;--metadata&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;questions&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;./test_compile/&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;.html&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$file_name&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;xargs runs in a different process, so the function &lt;cite&gt;gen_html&lt;/cite&gt; will not
be available for that. To fix this, we first export it and then call it
with the xargs context. The &lt;cite&gt;_&lt;/cite&gt; is a place holder for &lt;cite&gt;argv[0]&lt;/cite&gt; and &lt;cite&gt;%&lt;/cite&gt;
is the parameter defined by &lt;cite&gt;-I&lt;/cite&gt;. See &lt;a class="reference external" href="https://stackoverflow.com/a/11003457"&gt;this link&lt;/a&gt;
for more information.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;gen_html
find&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;-maxdepth&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-type&lt;span class="w"&gt; &lt;/span&gt;f&lt;span class="w"&gt; &lt;/span&gt;-name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*.md&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-printf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%f\n&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sort&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xargs&lt;span class="w"&gt; &lt;/span&gt;-I&lt;span class="w"&gt; &lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;bash&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gen_html &amp;quot;$@&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;_&lt;span class="w"&gt; &lt;/span&gt;%
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After which I generate the index with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pandoc&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;markdown&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;html&lt;span class="w"&gt; &lt;/span&gt;--mathjax&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;./test_compile/index.html&lt;span class="w"&gt; &lt;/span&gt;index.md
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can find the full code in &lt;a class="reference external" href="https://gist.github.com/jnduli/0d07305c79c542282d105c48e31d004c"&gt;this gihub gist&lt;/a&gt;.&lt;/p&gt;
</content><category term="Engineering"/></entry><entry><title>Comment System Using Recursive Queries</title><link href="https://blog.jnduli.co.ke/comment-system-using-recursive-queries.html" rel="alternate"/><published>2021-06-26T00:00:00+03:00</published><updated>2021-06-26T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2021-06-26:/comment-system-using-recursive-queries.html</id><summary type="html">&lt;p&gt;I was reading SQL antipatterns and got into the chapter about recursive
queries and how there are different ways to approach this. I wanted to
experiment with this and found that postgresql supports recursive
queries. I decided to make a simple commenting database and see how it
would work.&lt;/p&gt;
&lt;div class="section" id="fibonnacci-with-ctes"&gt;
&lt;h2&gt;Fibonnacci …&lt;/h2&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I was reading SQL antipatterns and got into the chapter about recursive
queries and how there are different ways to approach this. I wanted to
experiment with this and found that postgresql supports recursive
queries. I decided to make a simple commenting database and see how it
would work.&lt;/p&gt;
&lt;div class="section" id="fibonnacci-with-ctes"&gt;
&lt;h2&gt;Fibonnacci with CTEs&lt;/h2&gt;
&lt;p&gt;Adopted from &lt;a class="reference external" href="https://wiki.postgresql.org/wiki/Fibonacci_Numbers"&gt;https://wiki.postgresql.org/wiki/Fibonacci_Numbers&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RECURSIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;-- non recursive part --&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;-- recursive part --&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;limit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here's how this would work:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;There are three tables, intermediate, working and result table. The
non-recursive part is first calculated, setting the working and
result table to values (0, 1)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;The recursive part of the query &lt;cite&gt;select b, a + b from fib&lt;/cite&gt; is then
run on. &lt;cite&gt;fib&lt;/cite&gt; here is the working table, which contains (0, 1).  This
sets the intermediate table to (1, 1). This gets appended to the result
table, and replaces the working table.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;In the next run, the working table is (1, 1), resulting in (1, 2) in
the intermediate table, which gets appended to the result table, and
replaces the working table. This goes on and on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;The recursion should stop when the intermediate table is empty but
since fibonacci is infinite this does not happen. Adding a where
clause to the recursive part would cause this to occur. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RECURSIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;-- non recursive part --&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;-- recursive part --&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;The last select statement: &lt;cite&gt;SELECT a from fib limit 20;&lt;/cite&gt; picks the
information from the result table. Limiting this too can cause the
infinite recursion to stop.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Detailed explanation of how this works can be found here:
&lt;a class="reference external" href="https://wiki.postgresql.org/wiki/CTEReadme"&gt;CTE Read me&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="comment-system"&gt;
&lt;h2&gt;Comment System&lt;/h2&gt;
&lt;p&gt;Here's the table structure I used:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;SERIAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;date_created&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;date_created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;parent 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;parent 2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child of 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-02&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;another child of 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-03&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child of 2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-03&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child of 3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-03&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child of 6&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-04&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child of 7&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-05&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child of 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-06&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child of 5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2021-01-05&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A simple recursive query getting all children for comment_id 1 is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RECURSIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A good use case is when you have partitioned tables and want to see all
descendant of a particular parent.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;topic_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HASH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remainder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HASH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remainder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;grand_child_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remainder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;grand_child_2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remainder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RECURSIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_partition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inhparent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inhrelid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pg_inherits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inhparent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;parent&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;regclass&lt;/span&gt;
&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inhparent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inhrelid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pg_inherits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_partition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inhparent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inhrelid&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inhparent&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;regclass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inhrelid&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;regclass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_partition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which results in:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;
&lt;span class="c1"&gt;---------+---------------&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_1&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_2&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;grand_child_1&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;grand_child_2&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="cycle-prevention"&gt;
&lt;h2&gt;Cycle Prevention&lt;/h2&gt;
&lt;p&gt;To introduce a cycle in this query we just have to do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To prevent this while running our query, we have to keep a state of all
the parents we've visited and filter these out in the recursive bit. In
this case, we maintain an array of visited parents and ignore all
children comments that have that id.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RECURSIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visited_parents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visited_parents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;visited_parents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ANY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visited_parents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;child_comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But how do we prevent cycle creation in the query itself? One method is
to have a trigger that gets all parents of a child comment, and doesn't
update if the update would cause a cycle.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cycle_prevention&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;trigger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;cycle_prevention$&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;parents_not_allowed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;-- Check that parent id doesn&amp;#39;t cause a cycle&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;raise&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;notice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;parent id: %, comment_id %&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RECURSIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;UNION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parents_not_allowed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;raise&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;notice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Value: %&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parents_not_allowed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parents_not_allowed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;RAISE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXCEPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cycle found in query&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;cycle_prevention$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LANGUAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plpgsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRIGGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cycle_prevention&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEFORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EACH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cycle_prevention&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the update fails with &lt;cite&gt;ERROR:  cycle found in query&lt;/cite&gt;.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Engineering"/></entry><entry><title>TaskLite Setup</title><link href="https://blog.jnduli.co.ke/tasklite-setup.html" rel="alternate"/><published>2021-05-01T00:00:00+03:00</published><updated>2021-05-01T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2021-05-01:/tasklite-setup.html</id><summary type="html">&lt;p&gt;I used vimwiki for task management, with a couple of custom snippets and
scripts, but this quickly became complicated. I needed another tool that
would be easy to use, easy to understand and easy to tweak. TaskLite fit
these conditions perfectly:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;It's build on haskell and sqlite, a language and …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;I used vimwiki for task management, with a couple of custom snippets and
scripts, but this quickly became complicated. I needed another tool that
would be easy to use, easy to understand and easy to tweak. TaskLite fit
these conditions perfectly:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;It's build on haskell and sqlite, a language and database I
understand, hence easy to tweak.&lt;/li&gt;
&lt;li&gt;It has excellent &lt;a class="reference external" href="https://tasklite.org/"&gt;documentation&lt;/a&gt;,
hence easy to use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To set up tasklite:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;yay&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;stack-static&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# this provides statically linked libraries&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://github.com/ad-si/TaskLite.git
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;TaskLite
stack&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;tasklite-core
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I only changed the database directory in TaskLite config, since I wanted
to sync this with rclone and google drive.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;config&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;tasklite&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;yaml&lt;/span&gt;
&lt;span class="nv"&gt;dataDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/&lt;/span&gt;&lt;span class="py"&gt;gdrive_rclone&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;tasklite&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using tasklite is easy. Here are some common commands I use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tl&lt;span class="w"&gt; &lt;/span&gt;tasklite
tl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;help&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# show help&lt;/span&gt;
tl&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;book&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# add task&lt;/span&gt;
tl&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;meeting&lt;span class="w"&gt; &lt;/span&gt;due:2021-04-28T10:00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# add task with due date&lt;/span&gt;
tl&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;invest&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;stocks&lt;span class="w"&gt; &lt;/span&gt;+finances&lt;span class="w"&gt; &lt;/span&gt;due:2021-04-28T10:00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# add task with due date and tag (finances)&lt;/span&gt;
tl&lt;span class="w"&gt; &lt;/span&gt;due&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2021&lt;/span&gt;-04-28T10:00&lt;span class="w"&gt; &lt;/span&gt;task_id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# add due date to a task&lt;/span&gt;
tl&lt;span class="w"&gt; &lt;/span&gt;recur&lt;span class="w"&gt; &lt;/span&gt;P1D&lt;span class="w"&gt; &lt;/span&gt;task_id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# add recurrence period for tasklite&lt;/span&gt;
tl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;task_id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# mark a task as done&lt;/span&gt;
tl&lt;span class="w"&gt; &lt;/span&gt;delete&lt;span class="w"&gt; &lt;/span&gt;task_id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# delete a task&lt;/span&gt;
tl&lt;span class="w"&gt; &lt;/span&gt;edit&lt;span class="w"&gt; &lt;/span&gt;task_id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# edit a task in my $EDITOR&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some quirks I've encountered though are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;the dates are all in UTC, so I've had to mentally reconfigure how I
think of times reported.&lt;/li&gt;
&lt;li&gt;by default the task ids are usually listed truncated to the last n
characters e.g. 4 if the list has 20 items. This will sometimes cause
conflicts when using the task_id.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="recurring-and-repeating-tasks"&gt;
&lt;h2&gt;Recurring and Repeating Tasks&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="https://tasklite.org/repetition_and_recurrence.html"&gt;Recurring and Repeating Tasks Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To understand how I use recurring and repeating tasks, let's say I want
to clean my desk every day at 1300 Hrs. I can either set this as
recurring P1D or repeating P1D.&lt;/p&gt;
&lt;p&gt;If the task was created on Monday and it's recurring, once I'm done, a
new task with a due date of Tuesday 1300 Hrs will be created (even if I
completed the task on Wednesday). So completion time does not matter
when a task is recurring.&lt;/p&gt;
&lt;p&gt;If this task was repeating, the new task would be created with a due
date relative to the time I completed the task. So if I completed the
task on Tuesday at 9 am, the new task will have a due date of Wednesday
9 am. I use recurring tasks more.&lt;/p&gt;
&lt;p&gt;Other durations like P1M, P2W are supported. See &lt;a class="reference external" href="https://en.wikipedia.org/wiki/ISO_8601#Durations"&gt;ISO 8601 durations&lt;/a&gt; for more.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;tl&lt;span class="w"&gt; &lt;/span&gt;recur&lt;span class="w"&gt; &lt;/span&gt;P1D&lt;span class="w"&gt; &lt;/span&gt;task_id
tl&lt;span class="w"&gt; &lt;/span&gt;repeat&lt;span class="w"&gt; &lt;/span&gt;P1D&lt;span class="w"&gt; &lt;/span&gt;task_id
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When the new task is created, tags are copied over but not notes
however.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="syncing"&gt;
&lt;h2&gt;Syncing&lt;/h2&gt;
&lt;p&gt;I needed a way to sync things up across multiple laptops. I use rclone,
but since it doesn't have bi-sync, I had to get a little creative to
pull this off. I use the copy command with the &lt;cite&gt;--update&lt;/cite&gt; flag, which
only copies files over when the destinations' modified time is less than
the source.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;*/1 * * * * /usr/bin/rclone copy /home/rookie/gdrive_clone gdrive:backups/work_xps/ --update
*/1 * * * * /usr/bin/rclone copy gdrive:backups/work_xps/ /home/rookie/gdrive_clone --update
00 18 * * * /home/rookie/.local/bin/tasklite backup
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Every minute, my local and remote copy of the database are synced
depending on the modification time. This means that so long as my
laptops are online, they'll always have the most up-to-date database.
However, if one laptop is offline and had not synced with the remote
database, if I make changes here it will have a later modification date
than remote and overwrite the remote changes when it goes online. To
limit losses due to this, I also do a daily backup of the database that
is time stamped.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="helper-commands"&gt;
&lt;h2&gt;Helper Commands&lt;/h2&gt;
&lt;p&gt;Since sqlite is used as the storage engine, I can make custom queries.
Tasklite supports this using the &lt;cite&gt;tasklite query&lt;/cite&gt; command. I've made
some aliases in my zsh config for most common tasks I do.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;tl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tasklite&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;# all ready tasks with a due date of today&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tl-leo&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tl query \&amp;quot;closed_utc IS NULL AND DATE(due_utc) &amp;lt;= DATE(&amp;#39;now&amp;#39;) AND (ready_utc IS NULL OR DATETIME(ready_utc) &amp;lt;= DATETIME(&amp;#39;now&amp;#39;)) order by due_utc ASC, ready_utc ASC, priority DESC\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;# all tasks with a due date of today&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tl-leo-all&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tl query \&amp;quot;closed_utc IS NULL AND DATE(due_utc) &amp;lt;= DATE(&amp;#39;now&amp;#39;) order by due_utc ASC\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;# all tasks with a due date of tomorrow&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tl-kesho&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tl query \&amp;quot;closed_utc IS NULL AND DATE(due_utc) &amp;lt;= DATE(&amp;#39;now&amp;#39;, &amp;#39;+1 day&amp;#39;) order by due_utc ASC\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;# all unscheduled tasks&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tl-unscheduled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tl query \&amp;quot;closed_utc IS NULL AND due_utc IS NULL order by priority DESC\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;# syncing commands&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tl-down&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rclone copy gdrive:backups/work_xps ~/gdrive_rclone --update&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tl-up&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rclone copy ~/gdrive_rclone gdrive:backups/work_xps --update&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
</content><category term="Computer"/></entry><entry><title>Copying Pass Secrets to Another Machine</title><link href="https://blog.jnduli.co.ke/copying-pass-secrets-to-another-machine.html" rel="alternate"/><published>2021-03-27T00:00:00+03:00</published><updated>2021-03-27T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2021-03-27:/copying-pass-secrets-to-another-machine.html</id><summary type="html">&lt;p&gt;I had a new laptop but couldn't access my previous one, so I had to
figure out how to get my &lt;a class="reference external" href="https://www.passwordstore.org/"&gt;pass&lt;/a&gt;
secrets. I had these problems:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;How would I get my old password store?&lt;/li&gt;
&lt;li&gt;How would I be able get my old gpg keys into this new laptop?&lt;/li&gt;
&lt;li&gt;I …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;I had a new laptop but couldn't access my previous one, so I had to
figure out how to get my &lt;a class="reference external" href="https://www.passwordstore.org/"&gt;pass&lt;/a&gt;
secrets. I had these problems:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;How would I get my old password store?&lt;/li&gt;
&lt;li&gt;How would I be able get my old gpg keys into this new laptop?&lt;/li&gt;
&lt;li&gt;I had started storing new passwords using a new gpg key, so how would
this work the old password store (generated with a different key)?&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="getting-the-old-secrets"&gt;
&lt;h2&gt;Getting the old secrets&lt;/h2&gt;
&lt;p&gt;My home directory was compressed using &lt;a class="reference external" href="https://borgbackup.readthedocs.io/en/stable/"&gt;borg&lt;/a&gt; and sent to me using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;borg&lt;span class="w"&gt; &lt;/span&gt;init&lt;span class="w"&gt; &lt;/span&gt;/path/to/folder
borg&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;--progess&lt;span class="w"&gt; &lt;/span&gt;/path/to/backup::susa&lt;span class="w"&gt; &lt;/span&gt;/home/username
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And on my laptop I ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;borg&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;backup::susa-initial&lt;span class="w"&gt; &lt;/span&gt;/home/username/borg_mount
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This folder is mounted as read only, limiting what I could do in it.
Here are some of the errors I got because of this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;gpg&lt;span class="w"&gt; &lt;/span&gt;--homedir&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--list-keys
gpg:&lt;span class="w"&gt; &lt;/span&gt;failed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;temporary&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/home/username/borg_mount/home/username/.password-store/.#lk0x000055b881984170.archlinux.39288&amp;#39;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Read-only&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;system
gpg:&lt;span class="w"&gt; &lt;/span&gt;keyblock&lt;span class="w"&gt; &lt;/span&gt;resource&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/home/username/borg_mount/home/username/.password-store/pubring.kbx&amp;#39;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Read-only&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;system
gpg:&lt;span class="w"&gt; &lt;/span&gt;failed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;temporary&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/home/username/borg_mount/home/username/.password-store/.#lk0x000055b881981700.archlinux.39288&amp;#39;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Read-only&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;system
gpg:&lt;span class="w"&gt; &lt;/span&gt;Fatal:&lt;span class="w"&gt; &lt;/span&gt;can&lt;span class="s1"&gt;&amp;#39;t create lock for &amp;#39;&lt;/span&gt;/home/username/borg_mount/home/username/.password-store/trustdb.gpg&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I copied over the gpg key into a folder outside the mounted borg folder:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;borg_mount/home/username/.gnupg/*&lt;span class="w"&gt; &lt;/span&gt;gpg_tests/
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gpg_tests
gpg&lt;span class="w"&gt; &lt;/span&gt;--homedir&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--list-keys&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# this now works&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And exported my keys with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;gpg&lt;span class="w"&gt; &lt;/span&gt;--homedir&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="w"&gt; &lt;/span&gt;personal_gpg.gpg&lt;span class="w"&gt; &lt;/span&gt;--armor&lt;span class="w"&gt; &lt;/span&gt;--export&lt;span class="w"&gt; &lt;/span&gt;ID_FOR_KEY
gpg&lt;span class="w"&gt; &lt;/span&gt;--homedir&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="w"&gt; &lt;/span&gt;personal_sec.gpg&lt;span class="w"&gt; &lt;/span&gt;--armor&lt;span class="w"&gt; &lt;/span&gt;--export-secret-keys&lt;span class="w"&gt; &lt;/span&gt;ID_FOR_KEY
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I imported them them with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;gpg&lt;span class="w"&gt; &lt;/span&gt;--import&lt;span class="w"&gt; &lt;/span&gt;personal_gpg.gpg
gpg&lt;span class="w"&gt; &lt;/span&gt;--allow-secret-key-import&lt;span class="w"&gt; &lt;/span&gt;--import&lt;span class="w"&gt; &lt;/span&gt;personal_sec.gpg
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="working-with-both-password-stores"&gt;
&lt;h2&gt;Working with both password stores&lt;/h2&gt;
&lt;p&gt;Pass stores the &lt;cite&gt;gpg_id&lt;/cite&gt; in its root folder, so I just copied over the
previous pass store into a subdirectory in my new password store.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;home/username/.password_store&lt;span class="w"&gt; &lt;/span&gt;~/.password_store/oldpasswords
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now running pass shows all my passwords, both on from my old laptop and
new laptop. It's a little inconvenient because I now have an extra node
to go through to access my old passwords but this is an acceptable
compromise.&lt;/p&gt;
&lt;p&gt;Another unexplored alternative is to convert all the old passwords to
use the new gpg key. It should be a simple script that just gets the
password from the old gpg key and saves it into the new store.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Engineering"/></entry><entry><title>Thinkpad T440 ArchLinux Setup</title><link href="https://blog.jnduli.co.ke/thinkpad-t440-archlinux-setup.html" rel="alternate"/><published>2021-02-27T00:00:00+03:00</published><updated>2021-02-27T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2021-02-27:/thinkpad-t440-archlinux-setup.html</id><summary type="html">&lt;p&gt;I recently got a Thinkpad T440 and decided to document the steps I took
to set up archlinux. The last time I'd done this was on the &lt;a class="reference external" href="https://blog.jnduli.co.ke/asus-zenbook-archlinux-setup.html"&gt;Asus
Zenbook UX330UA&lt;/a&gt; some
years back. I thought the process would be different, but it was largely
similar.&lt;/p&gt;
&lt;p&gt;I first got the iso …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently got a Thinkpad T440 and decided to document the steps I took
to set up archlinux. The last time I'd done this was on the &lt;a class="reference external" href="https://blog.jnduli.co.ke/asus-zenbook-archlinux-setup.html"&gt;Asus
Zenbook UX330UA&lt;/a&gt; some
years back. I thought the process would be different, but it was largely
similar.&lt;/p&gt;
&lt;p&gt;I first got the iso image and burnt it onto a flash drive with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;dd&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;archlinux-2021.01.01-x86_64.iso&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sda&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;progress&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2M
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Connecting the flash into the laptop and booting got me into Grub, then
archlinux, and accessed wifi using &lt;a class="reference external" href="https://wiki.archlinux.org/index.php/Iwd"&gt;iwctl&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;iwctl
device&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# showed wlan0 as the wifi device&lt;/span&gt;
station&lt;span class="w"&gt; &lt;/span&gt;wlan0&lt;span class="w"&gt; &lt;/span&gt;scan
station&lt;span class="w"&gt; &lt;/span&gt;wlan0&lt;span class="w"&gt; &lt;/span&gt;get-networks&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# list SSIDs&lt;/span&gt;
station&lt;span class="w"&gt; &lt;/span&gt;wlan0&lt;span class="w"&gt; &lt;/span&gt;connect&lt;span class="w"&gt; &lt;/span&gt;SSID
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After which I updated the system clock with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;timedatectl&lt;span class="w"&gt; &lt;/span&gt;set-ntp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I had no qualms wiping out my hard drive and setting things up from
scratch. I noticed that I had two storage devices, a 16GB SSD and a 512GB
hard drive. I decided against using the SSD for anything (I'm planning
to upgrade this to a larger size), and only used the hard drive.&lt;/p&gt;
&lt;p&gt;To partition the drive:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;fdisk&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# lists devices&lt;/span&gt;

fdisk&lt;span class="w"&gt; &lt;/span&gt;/dev/sda&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# enters fdisk to help modify this drive&lt;/span&gt;
g&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# convert to gpt partitioning scheme&lt;/span&gt;
n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# create a new partition&lt;/span&gt;
&lt;span class="c1"&gt;# first partition 2M for Grub, mark this as Bios boot&lt;/span&gt;
n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 2nd partition 120GB for linux&lt;/span&gt;
n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# 3rd partittion rest of files size, for home directory&lt;/span&gt;
w&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# write changes and exit&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first partition needed to have at least 1MB for Grub (see &lt;a class="reference external" href="https://wiki.archlinux.org/index.php/GRUB#GUID_Partition_Table_(GPT)_specific_instructions)"&gt;grub
archwiki&lt;/a&gt;.
I added another two partitions: 120GB for arch and the rest for my home
folder. My reasoning was that when I upgraded the SSD, I'd just set up
arch on it and my home folder would still be ok.&lt;/p&gt;
&lt;p&gt;I partitioned the 2nd partition with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkfs.ext4&lt;span class="w"&gt; &lt;/span&gt;/dev/sda2
mount&lt;span class="w"&gt; &lt;/span&gt;/dev/sda2&lt;span class="w"&gt; &lt;/span&gt;/mnt
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And installed most of the programs I'd need with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pacstrap&lt;span class="w"&gt; &lt;/span&gt;/mnt&lt;span class="w"&gt; &lt;/span&gt;base&lt;span class="w"&gt; &lt;/span&gt;linux&lt;span class="w"&gt; &lt;/span&gt;linux-firmware&lt;span class="w"&gt; &lt;/span&gt;openssh&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;networkmanager&lt;span class="w"&gt; &lt;/span&gt;tmux&lt;span class="w"&gt; &lt;/span&gt;i3&lt;span class="w"&gt; &lt;/span&gt;dmenu&lt;span class="w"&gt; &lt;/span&gt;sway&lt;span class="w"&gt; &lt;/span&gt;xfce4&lt;span class="w"&gt; &lt;/span&gt;feh&lt;span class="w"&gt; &lt;/span&gt;scrot&lt;span class="w"&gt; &lt;/span&gt;xautolock&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;python-pip&lt;span class="w"&gt; &lt;/span&gt;gvim&lt;span class="w"&gt; &lt;/span&gt;neovim&lt;span class="w"&gt; &lt;/span&gt;python-pynvim&lt;span class="w"&gt; &lt;/span&gt;xdg-user-dirs&lt;span class="w"&gt; &lt;/span&gt;zsh&lt;span class="w"&gt; &lt;/span&gt;zsh-completions&lt;span class="w"&gt; &lt;/span&gt;pulseaudio&lt;span class="w"&gt; &lt;/span&gt;ledger&lt;span class="w"&gt; &lt;/span&gt;firefox&lt;span class="w"&gt; &lt;/span&gt;libmtp&lt;span class="w"&gt; &lt;/span&gt;gvfs-mtp&lt;span class="w"&gt; &lt;/span&gt;man-db&lt;span class="w"&gt; &lt;/span&gt;man-pages&lt;span class="w"&gt; &lt;/span&gt;texinfo&lt;span class="w"&gt; &lt;/span&gt;intel-ucode&lt;span class="w"&gt; &lt;/span&gt;grub
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To generate fstab, I first mounted the third partition into &lt;cite&gt;/mnt/home&lt;/cite&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkfs.ext4&lt;span class="w"&gt; &lt;/span&gt;/dev/sda3&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# partition to ext4&lt;/span&gt;
mount&lt;span class="w"&gt; &lt;/span&gt;/dev/sda3&lt;span class="w"&gt; &lt;/span&gt;/mnt/home&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# ensures home is on another partition&lt;/span&gt;
genfstab&lt;span class="w"&gt; &lt;/span&gt;-U&lt;span class="w"&gt; &lt;/span&gt;/mnt&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/mnt/etc/fstab
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then chroot'ed into the partition and set up my timezone, locale and
root user.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;arch-chroot&lt;span class="w"&gt; &lt;/span&gt;/mnt
ln&lt;span class="w"&gt; &lt;/span&gt;-sf&lt;span class="w"&gt; &lt;/span&gt;/usr/share/zoneinfo/Africa/Nairobi&lt;span class="w"&gt; &lt;/span&gt;/etc/localtime
hwclock&lt;span class="w"&gt; &lt;/span&gt;--systohc
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I set the locale by uncommenting the 'en_US.UTF-8 UTF-8' and the
'en_GB.UTF-8 UTF-8' lines in the /etc/locale.gen file and ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;locale-gen
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/locale.conf
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ovonel&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/hostname
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and added the following lines into &lt;cite&gt;/etc/hosts&lt;/cite&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;127.0.0.1   localhost
::1             localhost
127.0.1.1   ovonel.localdomain ovonel
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I set up the root password by typing &lt;cite&gt;passwd&lt;/cite&gt;, and added a new user
with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;useradd&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;-G&lt;span class="w"&gt; &lt;/span&gt;wheel&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/bin/bash&lt;span class="w"&gt; &lt;/span&gt;username
passwd&lt;span class="w"&gt; &lt;/span&gt;username
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I also installed sudo and set up permissions for the wheel group by
uncommenting the line &lt;cite&gt;%WHEEL  ALL= (ALL) ALL&lt;/cite&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;sudo
&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vi&lt;span class="w"&gt; &lt;/span&gt;visudo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#and uncommnet the line %WHEEL  ALL= (ALL) ALL&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lastly I set up grub with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;grub-install&lt;span class="w"&gt; &lt;/span&gt;/dev/sda
grub-mkconfig&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;/boot/grub/grub.cfg
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and after rebooting, I could enter my system.&lt;/p&gt;
&lt;div class="section" id="other-thinkpad-t440-specific-things"&gt;
&lt;h2&gt;Other Thinkpad T440 specific Things&lt;/h2&gt;
&lt;p&gt;This section will keep getting updates as I slowly improve my linux
experience on the laptop.&lt;/p&gt;
&lt;p&gt;I installed xorg using the instructions &lt;a class="reference external" href="https://wiki.archlinux.org/index.php/Xorg"&gt;xorg archwiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had to fix the screen size by measuring my screen dimensions with a tape
measure and added them in a monitor config in
&lt;cite&gt;/etc/X11/xorg.conf.d/90.monitor.conf&lt;/cite&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Section &amp;quot;Monitor&amp;quot;
    Identifier      &amp;quot;eDP1&amp;quot;
    DisplaySize     300 170
    Gamma           0.7
EndSection
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For power management I set up tpacpi-bat and tlp, enabling their default
services.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pacman&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;tpacpi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;bat&lt;/span&gt;
&lt;span class="nv"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;systemctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;tpacpi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;bat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;service&lt;/span&gt;
&lt;span class="nv"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pacman&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;S&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;tlp&lt;/span&gt;
&lt;span class="nv"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;systemctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;tlp&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>Setting up Hspec on a Haskell Project</title><link href="https://blog.jnduli.co.ke/setting-up-hspec-on-haskell-project.html" rel="alternate"/><published>2021-01-23T00:00:00+03:00</published><updated>2021-01-23T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2021-01-23:/setting-up-hspec-on-haskell-project.html</id><summary type="html">&lt;p&gt;I'd started the &lt;a class="reference external" href="https://github.com/jnduli/kindle_highlights"&gt;Kindle-Highlights project&lt;/a&gt; without tests. This was
a problem because I couldn't add features as fast as I wanted because
I'd break something without knowing. I needed to add tests to speed up
my development. For haskell, &lt;a class="reference external" href="https://hspec.github.io/"&gt;hspec&lt;/a&gt;  is a
tool/library for this. Setting this up on …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'd started the &lt;a class="reference external" href="https://github.com/jnduli/kindle_highlights"&gt;Kindle-Highlights project&lt;/a&gt; without tests. This was
a problem because I couldn't add features as fast as I wanted because
I'd break something without knowing. I needed to add tests to speed up
my development. For haskell, &lt;a class="reference external" href="https://hspec.github.io/"&gt;hspec&lt;/a&gt;  is a
tool/library for this. Setting this up on the project was surprisingly
challenging, mostly because I didn't properly read the docs.&lt;/p&gt;
&lt;p&gt;Some of the things I missed out on or had to do are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;There is auto detection of test files with &lt;a class="reference external" href="https://hspec.github.io/hspec-discover.html"&gt;hspec-discover&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Test files should have the suffix Spec (I'd added them with a Test
Suffix) to be auto discovered by hspec-discover.&lt;/li&gt;
&lt;li&gt;Each test file has to export a &lt;cite&gt;spec&lt;/cite&gt; of type Spec&lt;/li&gt;
&lt;li&gt;I needed to set up some of my modules properly in the cabal file.&lt;/li&gt;
&lt;li&gt;I had to move executable to a different directory to prevent warning
on missing dependencies, see &lt;a class="reference external" href="https://github.com/commercialhaskell/stack/issues/3109"&gt;github stack issue `&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I switched to cabal version 2.2 to use the shared properties field.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are the steps I took to having a properly working and tested code
base:&lt;/p&gt;
&lt;div class="section" id="cabal-setup"&gt;
&lt;h2&gt;Cabal Setup&lt;/h2&gt;
&lt;p&gt;I modified my cabal config by:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Using cabal version 2.2: this is so that I could use common stanzas
preventing duplication of dependencies, see &lt;a class="reference external" href="https://cabal.readthedocs.io/en/latest/developing-packages.html#common-stanzas"&gt;cabal common-stanzas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Adding a library section that exposed the modules that I wanted to
test.&lt;/li&gt;
&lt;li&gt;Adding a test section that contained hspec options.&lt;/li&gt;
&lt;li&gt;Added an executable section and moved the executable code &lt;cite&gt;Main.hs&lt;/cite&gt; to
another folder to prevent warning errors on missing dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cabal-version:       2.2
name:                kindle-highlights
.
.

common shared-properties
  default-language:    Haskell2010
  build-depends:       base &amp;gt;= 4.7 &amp;amp;&amp;amp; &amp;lt; 5,
                       parsec,
                       text,
                       containers,
                       time

library
  import:              shared-properties
  exposed-modules:     KindleHighlights,
                       CommandOptions
  hs-source-dirs:      src
  build-depends:       optparse-applicative

executable kindle-highlights
  import:              shared-properties
  hs-source-dirs:      app
  main-is:             Main.hs
  build-depends:       optparse-applicative,
                       kindle-highlights,

test-suite spec
  import:              shared-properties
  type:                exitcode-stdio-1.0
  hs-source-dirs:      test
  main-is:             Spec.hs
  other-modules:       ParserSpec
  build-depends:       kindle-highlights,
                       hspec &amp;gt;= 2.7,
                       hspec-discover &amp;gt;= 2.7
  ghc-options: -Wall
  build-tool-depends: hspec-discover:hspec-discover == 2.*
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Key things here are that the test-suite spec points to the 'test'
directory, with &lt;cite&gt;hspec&lt;/cite&gt; and &lt;cite&gt;hspec-discover&lt;/cite&gt; added as build-depends.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="writing-the-tests"&gt;
&lt;h2&gt;Writing the Tests&lt;/h2&gt;
&lt;p&gt;To enable automatic test discovery, the &lt;cite&gt;Spec.hs&lt;/cite&gt; file has:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cm"&gt;{-# OPTIONS_GHC -F -pgmF hspec-discover #-}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which means it will automatically pick up tests that I write. The test
files has to have the &lt;cite&gt;Spec&lt;/cite&gt; suffix for this to work.&lt;/p&gt;
&lt;p&gt;To write a test file, for example, &lt;cite&gt;ParserSpec.hs&lt;/cite&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;ParserSpec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="nf"&gt;spec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Spec&lt;/span&gt;
&lt;span class="nf"&gt;spec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;KindleHighlights&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;has a string definition for end of group&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;eogString&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;shouldBe&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;==========&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;has to export the spec function, which will be called by hspec.&lt;/p&gt;
&lt;p&gt;Running the tests with &lt;cite&gt;stack test&lt;/cite&gt; should show:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;kindle-highlights&amp;gt; test (suite: spec)

Progress 1/2: kindle-highlights
Parser
  KindleHighlights
    has a string definition for end of group
    highlights
    highlights 2
    groups

Finished in 0.0004 seconds
4 examples, 0 failures

kindle-highlights&amp;gt; Test suite spec passed
Completed 2 action(s).
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which shows the tests ran successfully.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Engineering"/><category term="projects"/></entry><entry><title>Custom snippets in vim</title><link href="https://blog.jnduli.co.ke/custom-snippets-in-vim.html" rel="alternate"/><published>2020-08-30T00:00:00+03:00</published><updated>2020-08-30T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2020-08-30:/custom-snippets-in-vim.html</id><summary type="html">&lt;div class="section" id="set-up"&gt;
&lt;h2&gt;Set up&lt;/h2&gt;
&lt;p&gt;I use &lt;a class="reference external" href="https://github.com/SirVer/ultisnips"&gt;ultisnips&lt;/a&gt; for my
snippets. To set this up, I have this in &lt;cite&gt;vimrc&lt;/cite&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; plug#begin&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;~/.vim/plugged&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

Plug &lt;span class="s1"&gt;&amp;#39;SirVer/ultisnips&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; Plug &lt;span class="s1"&gt;&amp;#39;honza/vim-snippets&amp;#39;&lt;/span&gt; &lt;span class="c"&gt;&amp;quot; Snippet support&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt; plug#&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:UltiSnipsExpandTrigger&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;c-e&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="c"&gt;&amp;quot; Default is &amp;lt;tab&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:UltiSnipsEditSplit&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:UltiSnipsSnippetDirectories&lt;span class="p"&gt;=&lt;/span&gt;[&lt;span class="s2"&gt;&amp;quot;UltiSnips&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;mysnippets&amp;quot;&lt;/span&gt;]
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="set-up"&gt;
&lt;h2&gt;Set up&lt;/h2&gt;
&lt;p&gt;I use &lt;a class="reference external" href="https://github.com/SirVer/ultisnips"&gt;ultisnips&lt;/a&gt; for my
snippets. To set this up, I have this in &lt;cite&gt;vimrc&lt;/cite&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; plug#begin&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;~/.vim/plugged&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

Plug &lt;span class="s1"&gt;&amp;#39;SirVer/ultisnips&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; Plug &lt;span class="s1"&gt;&amp;#39;honza/vim-snippets&amp;#39;&lt;/span&gt; &lt;span class="c"&gt;&amp;quot; Snippet support&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt; plug#&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:UltiSnipsExpandTrigger&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;c-e&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="c"&gt;&amp;quot; Default is &amp;lt;tab&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:UltiSnipsEditSplit&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:UltiSnipsSnippetDirectories&lt;span class="p"&gt;=&lt;/span&gt;[&lt;span class="s2"&gt;&amp;quot;UltiSnips&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;mysnippets&amp;quot;&lt;/span&gt;]
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This setups &lt;cite&gt;ultisnips&lt;/cite&gt; and &lt;cite&gt;vimsnippets&lt;/cite&gt; using &lt;cite&gt;plug&lt;/cite&gt;. Whenever I have
a snippet I want to use, I press &lt;cite&gt;ctrl-e&lt;/cite&gt; and its expanded. I place
custom snippets in &lt;cite&gt;~/.vim/mysnippets&lt;/cite&gt;, so having &lt;cite&gt;UltiSnips&lt;/cite&gt; in the
&lt;cite&gt;UltiSnipsSnippetDirectories&lt;/cite&gt; parameters enables me to use both the
custom snippets and those provided by &lt;cite&gt;ultisnips/vimsnippets&lt;/cite&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="simple-snippet"&gt;
&lt;h2&gt;Simple snippet&lt;/h2&gt;
&lt;p&gt;I like to pre-plan my day, with most days having similar and unique
tasks. A snippet is a good use case for the similar tasks.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Basic Day&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Clean&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Bathe&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;brush&lt;/span&gt; &lt;span class="n"&gt;teeth&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;story&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Emails&lt;/span&gt; &lt;span class="n"&gt;cleanup&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Weekly&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;
&lt;span class="n"&gt;endsnippet&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can place this file in &lt;cite&gt;~/vim/mysnippets/all.snippet&lt;/cite&gt; and type &lt;cite&gt;bd&lt;/cite&gt;
in any file to expand this. This does not cover tasks that are similar,
but with small differences e.g. for clean up, it needs to be clean up
something. I then update the snippet to include this by having &lt;cite&gt;{$1:
utensils, desk, room}&lt;/cite&gt;. &lt;cite&gt;utensils, desk, room&lt;/cite&gt; in this case is the
default string.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Basic Day&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Clean&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;utensils&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Meditation&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;story&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Emails&lt;/span&gt; &lt;span class="n"&gt;cleanup&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Weekly&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;
&lt;span class="n"&gt;endsnippet&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now typing &lt;cite&gt;Ctrl-j&lt;/cite&gt; after the snippet has been expanded takes me to all
the points with this marking.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="advanced-snippets"&gt;
&lt;h2&gt;Advanced snippets&lt;/h2&gt;
&lt;p&gt;The simple snippet has some disadvantages like:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;I can't specify unique tasks for a particular day e.g. I take out
trash on Thursdays&lt;/li&gt;
&lt;li&gt;I can't specify different conditions for tasks e.g. I need to switch
out some tasks with my house mate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/SirVer/ultisnips/blob/7dc30c55e5c41c98a8c7421bb01fec1d559256fd/doc/UltiSnips.txt#L1411"&gt;Context aware snippets&lt;/a&gt;
help with this. A context (in UltiSnips) is a python function that
returns true. For example, I want to do some tasks depending on if its
the weekend or not.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;datetime&lt;/span&gt;
&lt;span class="n"&gt;endglobal&lt;/span&gt;

&lt;span class="c1"&gt;# weekday basic day&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;datetime.date.today().isoweekday()&amp;lt;=5&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Basic Day&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Clean&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;utensils&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Meditation&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;story&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Emails&lt;/span&gt; &lt;span class="n"&gt;cleanup&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Retrospection&lt;/span&gt;
&lt;span class="n"&gt;endsnippet&lt;/span&gt;

&lt;span class="c1"&gt;# weekend basic day&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;datetime.date.today().isoweekday()&amp;gt;5&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Weekend&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Clean&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;utensils&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Wash&lt;/span&gt; &lt;span class="n"&gt;house&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;clothes&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Meditation&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;story&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Emails&lt;/span&gt; &lt;span class="n"&gt;cleanup&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Weekly&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;
&lt;span class="n"&gt;endsnippet&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This works but creates a lot of repeated tasks between the weekday and
weekend. To avoid this, python code can be used directly within the
snippets, for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;datetime&lt;/span&gt;
&lt;span class="n"&gt;endglobal&lt;/span&gt;

&lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Basic Day&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Clean&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;utensils&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;`!&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;snip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;- [ ] Wash house and clothes&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isoweekday&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Meditation&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;story&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Exercise&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Emails&lt;/span&gt; &lt;span class="n"&gt;cleanup&lt;/span&gt;
&lt;span class="err"&gt;`!&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;snip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;- [ ] Retrospection&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isoweekday&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Emails&lt;/span&gt; &lt;span class="n"&gt;cleanup&lt;/span&gt;
&lt;span class="err"&gt;`!&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;snip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;- [ ] Weekly email&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isoweekday&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;span class="n"&gt;endsnippet&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To prevent the repetition of datetime methods, you can define a global
variable and use that instead.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;datetime&lt;/span&gt;

&lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isoweekday&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;endglobal&lt;/span&gt;

&lt;span class="c1"&gt;## in snippet have this&lt;/span&gt;
&lt;span class="err"&gt;`!&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;snip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;- [ ] Weekly email&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ultisnips provides a powerful tool to customize repeated texts depending
on the situation. Described in this article is one of the use cases I
have, and various options I use to make my snippets manageable.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="programming"/></entry><entry><title>First Haskell Parser (for Kindle Highlights)</title><link href="https://blog.jnduli.co.ke/first_haskell_parser_for_kindle.html" rel="alternate"/><published>2020-05-26T00:00:00+03:00</published><updated>2020-05-26T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2020-05-26:/first_haskell_parser_for_kindle.html</id><summary type="html">&lt;p&gt;Kindle saves highlights, bookmarks and notes in a &lt;cite&gt;My Clippings.txt&lt;/cite&gt;
file. I needed a way to parse it and filter out the content I wanted.
I also wanted to work on a parser in haskell, so this was a great
opportunity to get my hands dirty.&lt;/p&gt;
&lt;p&gt;I used stack …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Kindle saves highlights, bookmarks and notes in a &lt;cite&gt;My Clippings.txt&lt;/cite&gt;
file. I needed a way to parse it and filter out the content I wanted.
I also wanted to work on a parser in haskell, so this was a great
opportunity to get my hands dirty.&lt;/p&gt;
&lt;p&gt;I used stack to manage the project by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;stack&lt;span class="w"&gt; &lt;/span&gt;new&lt;span class="w"&gt; &lt;/span&gt;kindle-highlights&lt;span class="w"&gt; &lt;/span&gt;simple
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kindle-highlights
stack&lt;span class="w"&gt; &lt;/span&gt;setup
stack&lt;span class="w"&gt; &lt;/span&gt;ghci&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# launches haskell repl for project&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Within the &lt;cite&gt;ghci repl&lt;/cite&gt;, the following commands were useful when making
changes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;:load&lt;span class="w"&gt; &lt;/span&gt;Main
:r&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# reload changes made to code&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a class="reference external" href="https://hackage.haskell.org/package/parsec"&gt;Parsec&lt;/a&gt; is the library I
chose to use. To start of, I wanted to parse a simple string that had a
similar structure to the kindle file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nf"&gt;exampleString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;this&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;good&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;==========&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;anther&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;group&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;==========&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;cite&gt;exampleString&lt;/cite&gt; above contains two different highlights each
separated with &lt;cite&gt;==========&lt;/cite&gt;. To get a single group, I'd look for this
separator and collect the groups before this. To do this in parsec:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Text.Parsec&lt;/span&gt;


&lt;span class="nf"&gt;eogString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;eogString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;==========&amp;quot;&lt;/span&gt;

&lt;span class="nf"&gt;endOfGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;endOfGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eogString&lt;/span&gt;

&lt;span class="nf"&gt;kindleGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;kindleGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;manyTill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;anyChar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;endOfGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kindleGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;failed&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exampleString&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running &lt;cite&gt;test&lt;/cite&gt; in ghci returns &lt;cite&gt;Right &amp;quot;thisnisngoodn&amp;quot;&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;endOfGroup&lt;/cite&gt; is a parser that only matches the &lt;cite&gt;eogString&lt;/cite&gt;. This is
combined with the &lt;cite&gt;kindleGroup&lt;/cite&gt; to get all characters (using &lt;cite&gt;anyChar&lt;/cite&gt;)
until the &lt;cite&gt;endOfGroup&lt;/cite&gt; is found.&lt;/p&gt;
&lt;p&gt;All the groups can be got by building on this through:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nf"&gt;groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kindleGroup&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remainingGroups&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;remainingGroups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;remainingGroups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;&amp;#39;\&lt;/span&gt;&lt;span class="n"&gt;n&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;|&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fail&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exampleString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which results in &lt;cite&gt;Right [&amp;quot;thisnisngoodn&amp;quot;,&amp;quot;antherngroupn&amp;quot;]&lt;/cite&gt;.
Groups gets a group from the string, and passes the rest of the string
to the &lt;cite&gt;remainingGroups&lt;/cite&gt; function. This in turn checks if the first
character in the string is &lt;cite&gt;n&lt;/cite&gt; after which it calls groups on the
string less the starting &lt;cite&gt;n&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;The above gave me a good framework for working on the kindle highlighter
which has the general form:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;book&lt;span class="w"&gt; &lt;/span&gt;title
-&lt;span class="w"&gt; &lt;/span&gt;Your&lt;span class="w"&gt; &lt;/span&gt;Highlight&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;page&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;818&lt;/span&gt;-810&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Added&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;Wednestday,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;October&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2018&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;:41:47

the&lt;span class="w"&gt; &lt;/span&gt;actual&lt;span class="w"&gt; &lt;/span&gt;highlighted&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sections&lt;/span&gt;
&lt;span class="o"&gt;==========&lt;/span&gt;
book&lt;span class="w"&gt; &lt;/span&gt;title
-&lt;span class="w"&gt; &lt;/span&gt;Your&lt;span class="w"&gt; &lt;/span&gt;Highlight&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;page&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;818&lt;/span&gt;-810&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Added&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;Wednestday,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;October&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2018&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;:41:47

the&lt;span class="w"&gt; &lt;/span&gt;actual&lt;span class="w"&gt; &lt;/span&gt;highlighted&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sections&lt;/span&gt;
&lt;span class="o"&gt;==========&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is what I came up with for that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;-- test&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;highlight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fail&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exampleGroup&lt;/span&gt;

&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;manyTill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;anyChar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newline&lt;/span&gt;

&lt;span class="nf"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;between&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;- Your Highlight at location &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oneOf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; |&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;locationGroupings&lt;/span&gt;

&lt;span class="nf"&gt;locationGroupings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;many1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;digit&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;many1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;digit&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nf"&gt;highlight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;highlight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="nf"&gt;exampleGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Axiomatic (Greg Egan)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;- Your Highlight at location 3722-3722 | Added on Sunday, 28 October 2018 08:42:11&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;mind; maybe some dreams take shape only in the&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This results in &lt;cite&gt;Right [&amp;quot;Axiomatic (Greg Egan)&amp;quot;,&amp;quot;mind; maybe some dreams take shape only in the&amp;quot;,&amp;quot;3722&amp;quot;,&amp;quot;3722&amp;quot;]&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;To parse multiple groups, we just:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="py"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;[[String]]&lt;/span&gt;
&lt;span class="nv"&gt;groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;highlight&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;remainingGroups&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="py"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;remainingGroups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="py"&gt;Parsec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;st&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;[[String]]&lt;/span&gt;
&lt;span class="nv"&gt;remainingGroups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;|&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;parse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;groups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;fail&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;exampleGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;exampleGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This returns:&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;Right [[&amp;quot;Axiomatic (Greg Egan)&amp;quot;,&amp;quot;mind; maybe some dreams take shape only in the&amp;quot;,&amp;quot;3722&amp;quot;,&amp;quot;3722&amp;quot;],[&amp;quot;Axiomatic (Greg Egan)&amp;quot;,&amp;quot;mind; maybe some dreams take shape only in the&amp;quot;,&amp;quot;3722&amp;quot;,&amp;quot;3722&amp;quot;]]&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;The kindle format has more nuts than what the above demonstrates, but
nevertheless I had a lot of fun working with this.&lt;/p&gt;
</content><category term="Computer"/><category term="linux"/><category term="project"/></entry><entry><title>Hiding Toolbars in Firefox</title><link href="https://blog.jnduli.co.ke/hiding-toolbars-in-firefox.html" rel="alternate"/><published>2020-04-18T00:00:00+03:00</published><updated>2020-04-18T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2020-04-18:/hiding-toolbars-in-firefox.html</id><summary type="html">&lt;p&gt;While using i3, I've realized that a lot of screen real estate in
firefox is taken up with the tab and navigation bar. This isn't a
problem when its the only application open, but when some tiling has
been done, these two bars quickly become a barrier to usage, for …&lt;/p&gt;</summary><content type="html">&lt;p&gt;While using i3, I've realized that a lot of screen real estate in
firefox is taken up with the tab and navigation bar. This isn't a
problem when its the only application open, but when some tiling has
been done, these two bars quickly become a barrier to usage, for
example:&lt;/p&gt;
&lt;img alt="firefox with tabs" src="https://blog.jnduli.co.ke/images/firefox_with_tabs.png" /&gt;
&lt;p&gt;Because of this, I decided to hide these two bars. However, this could
not be done by either firefox options or plugins. I therefore had to
enable &lt;cite&gt;toolkit.legacyUserProfileCustomizations.stylesheets&lt;/cite&gt; by visiting
&lt;cite&gt;about:config&lt;/cite&gt; in the browser, searching for this, and setting it to
true. This would enable customization using a &lt;cite&gt;userChrome.css&lt;/cite&gt; template.&lt;/p&gt;
&lt;p&gt;I then visited &lt;cite&gt;about:profile&lt;/cite&gt;, noted the Root Directory for my primary
profile and created a &lt;cite&gt;chrome&lt;/cite&gt; folder in that directory. I then added
the &lt;cite&gt;userChrome.css&lt;/cite&gt; file in there with the contents:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt; * Reference: https://www.reddit.com/r/FirefoxCSS/comments/boetx7/annoying_page_jump_with_address_bar_autohide/engne27/&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="cm"&gt;/* Hide Tabbar until mouse is around it */&lt;/span&gt;

&lt;span class="n"&gt;#TabsToolbar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;customizing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;inFullscreen&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;#TabsToolbar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;hover&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;inFullscreen&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="n"&gt;#TabsToolbar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;within&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* 29px compact, 33px normal, YMMV */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/* Hide nav-bar until mouse hovers */&lt;/span&gt;
&lt;span class="n"&gt;#nav&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;customizing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;inFullscreen&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;overflow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;#nav&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;#navigator&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;toolbox&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;hover&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;inFullscreen&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;#nav&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;#navigator&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;toolbox&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;within&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;#nav&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The image below shows the result of this:&lt;/p&gt;
&lt;img alt="firefox with hidden tabs and navbar" src="https://blog.jnduli.co.ke/images/firefox_hidden_tabs.png" /&gt;
&lt;p&gt;For firefox 75 I had to disable this &lt;cite&gt;browser.urlbar.update1&lt;/cite&gt; for the
urlbar to stop behaving weirdly.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.userchrome.org/help-with-userchrome-css.html"&gt;https://www.userchrome.org/help-with-userchrome-css.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/Timvde/UserChrome-Tweaks/blob/master/toolbars/auto-hide.css"&gt;https://github.com/Timvde/UserChrome-Tweaks/blob/master/toolbars/auto-hide.css&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://support.mozilla.org/en-US/questions/1185760"&gt;https://support.mozilla.org/en-US/questions/1185760&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content><category term="Linux"/><category term="linux"/><category term="projects"/></entry><entry><title>Python Timeit with Partial</title><link href="https://blog.jnduli.co.ke/python-timeit-with-partial.html" rel="alternate"/><published>2019-07-20T00:00:00+03:00</published><updated>2019-07-20T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-07-20:/python-timeit-with-partial.html</id><summary type="html">&lt;p&gt;The &lt;a class="reference external" href="https://docs.python.org/3.7/library/timeit.html"&gt;timeit module&lt;/a&gt;
provides an easy way to time python code. I use it to check if a new
code implementation runs faster than an older implementation.&lt;/p&gt;
&lt;p&gt;Example usage of this is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;timeit&lt;/span&gt;

&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;list(range(100))&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hello World&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Timeit …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The &lt;a class="reference external" href="https://docs.python.org/3.7/library/timeit.html"&gt;timeit module&lt;/a&gt;
provides an easy way to time python code. I use it to check if a new
code implementation runs faster than an older implementation.&lt;/p&gt;
&lt;p&gt;Example usage of this is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;timeit&lt;/span&gt;

&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;list(range(100))&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hello World&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Timeit does not provide a means of setting function parameters. A quick
work around for this is to use &lt;a class="reference external" href="https://docs.python.org/3.7/library/functools.html?highlight=partial#functools.partial"&gt;partial&lt;/a&gt;.
Partial results in a new function with the arguments provided frozen.&lt;/p&gt;
&lt;p&gt;It can be used as shown:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;timeit&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;functools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;partial&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="n"&gt;double_5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;double_5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"/><category term="projects"/></entry><entry><title>Working With A Bad Codebase</title><link href="https://blog.jnduli.co.ke/working-with-a-bad-code-base.html" rel="alternate"/><published>2019-06-10T00:00:00+03:00</published><updated>2019-06-10T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-06-10:/working-with-a-bad-code-base.html</id><summary type="html">&lt;p&gt;I've worked with codebases that have made me frustrated. Some of the
&lt;cite&gt;**features**&lt;/cite&gt; I've seen include:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Naming the variables returned by a function &lt;cite&gt;$this&lt;/cite&gt; and &lt;cite&gt;$return&lt;/cite&gt;.&lt;/li&gt;
&lt;li&gt;Having different languages in the same project. For example, I got one
which had &lt;cite&gt;PHP&lt;/cite&gt;, &lt;cite&gt;Python&lt;/cite&gt;, &lt;cite&gt;Perl&lt;/cite&gt;, &lt;cite&gt;JavaScript (node in the backend)&lt;/cite&gt;
and &lt;cite&gt;c …&lt;/cite&gt;&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;I've worked with codebases that have made me frustrated. Some of the
&lt;cite&gt;**features**&lt;/cite&gt; I've seen include:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Naming the variables returned by a function &lt;cite&gt;$this&lt;/cite&gt; and &lt;cite&gt;$return&lt;/cite&gt;.&lt;/li&gt;
&lt;li&gt;Having different languages in the same project. For example, I got one
which had &lt;cite&gt;PHP&lt;/cite&gt;, &lt;cite&gt;Python&lt;/cite&gt;, &lt;cite&gt;Perl&lt;/cite&gt;, &lt;cite&gt;JavaScript (node in the backend)&lt;/cite&gt;
and &lt;cite&gt;c#&lt;/cite&gt;. Each language did not solve a unique and niche problem in
this case.&lt;/li&gt;
&lt;li&gt;Using 5 different ways to load JavaScript and CSS resources on the
client on the same project.&lt;/li&gt;
&lt;li&gt;God functions. These are functions that do everything and are
impossible to debug.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fixing such a codebase needs a lot of thought put into it. I found that
the following process works best for me.&lt;/p&gt;
&lt;div class="section" id="forgetting-your-ego"&gt;
&lt;h2&gt;Forgetting your ego&lt;/h2&gt;
&lt;p&gt;The first reaction I have tends to be my ego talking. This is because I
find better ways to fix the problems at hand. This is usually because I
don't have the context nor understand the problem.&lt;/p&gt;
&lt;p&gt;What I do is take a break, walk around and look at the codebase again
once I've cooled down. This provides some fresh perspective and I
sometimes find that the code is pretty decent. This occurs when I had
started looking at the worst done sections of the codebase. I also get
to see the code organisation and styles used by doing this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="discuss-with-management"&gt;
&lt;h2&gt;Discuss with Management&lt;/h2&gt;
&lt;p&gt;Have an honest discussion with management. If the code is bad, it means
that feature addition or bug fixes take a significant amount of time
even for simple things. This is worse still if you're new to the code
base but don't have someone to guide you through it (This has happened
once for me).&lt;/p&gt;
&lt;p&gt;Also make it clear that things will occasionally break, especially if
the project did not have tests.&lt;/p&gt;
&lt;p&gt;Try to come up with a good enough workflow that will prevent the same
thing happening again.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="documentation"&gt;
&lt;h2&gt;Documentation&lt;/h2&gt;
&lt;p&gt;Document everything. In my case, documentation means issues, code
comments and API docs.&lt;/p&gt;
&lt;div class="section" id="issues"&gt;
&lt;h3&gt;Issues&lt;/h3&gt;
&lt;p&gt;I have a policy of not working on anything if there isn't an issue for
it. This helps me keep track of all the problems discovered in the
system.&lt;/p&gt;
&lt;p&gt;The basic requirements I have for issues are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Clear unambiguous title&lt;/li&gt;
&lt;li&gt;Prepend the title with the type of issue. I usually have Bug,
Refactor, Feature, Documentation.&lt;/li&gt;
&lt;li&gt;The description of the issue should explain the problem
comprehensively. If it is a bug, include a method of replication.&lt;/li&gt;
&lt;li&gt;An implementation plan: This is where I draft an initial solution to
the problem. This doesn't need to be accurate, but at least the next
time I look at this issue I won't start from scratch.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I create issues for every problem I encounter, no matter how simple it
seems.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="comments"&gt;
&lt;h3&gt;Comments&lt;/h3&gt;
&lt;p&gt;If you spend more time than necessary figuring out what a function does,
take the time to comment this out. The next time you deal with the
function, the comments will help you out.&lt;/p&gt;
&lt;p&gt;If the problem is in the function design, the comments can be a huge
time saver when refactoring it.&lt;/p&gt;
&lt;p&gt;For God functions, I try to comment blocks that do one specific thing.
When refactoring, I'll try to make these blocks into individual
functions.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="coding-standard"&gt;
&lt;h2&gt;Coding Standard&lt;/h2&gt;
&lt;p&gt;Choose a coding standard and stick to it. Even better yet, you can look
for tools that ensure your code follows this standard. In my case, I use
pre-commit hooks to either block commits or lint my code before
committing anything. This prevents mistakes when I'm in a hurry or there
is a lot of pressure.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="ci-cd"&gt;
&lt;h2&gt;CI/CD&lt;/h2&gt;
&lt;p&gt;I try to set up CI/CD for automatic testing and deployment of my
projects. This catches some problems like linting errors and failing
tests. It also reduces normal access to production/testing servers.
This reduces the likelihood of making changes live.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="testing"&gt;
&lt;h2&gt;Testing&lt;/h2&gt;
&lt;p&gt;Testing is the best thing I've found when improving codebases. This is
because it forces good coding practices by default. For example, if you
encounter a God function, trying to test this will force you to break it
down into manageable blocks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="database-modification"&gt;
&lt;h2&gt;Database Modification&lt;/h2&gt;
&lt;p&gt;I tend to avoid changing the database at first. This is because there
are a lot of things that could have been done there that you might mess
up. Also, unless you're a database pro, it's safer to deal with the code
base first.&lt;/p&gt;
&lt;p&gt;For example, I met a database with virtual tables, procedures and
triggers. I only knew of these features, but had never actively used
them. The problem at hand seemed fixable from the db side, but I had not
factored in that the affected table linked up with multiple virtual
tables and triggers. Trying to change the database led to a disaster
that took me days to fix (I didn't even fix this, but reverted the
database back to the original form).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="others"&gt;
&lt;h2&gt;Others&lt;/h2&gt;
&lt;p&gt;If removing or renaming something, try to use &lt;cite&gt;grep&lt;/cite&gt; to make sure it
isn't referenced somewhere. This is especially true for tightly coupled
systems. I've found controller functions used in the weirdest of places
on some codebases.&lt;/p&gt;
&lt;p&gt;Try to check code quality using &lt;cite&gt;code climate&lt;/cite&gt;. Analyzing the json
provided, helps figure out the more problematic sections of code. Better
yet, you can use this as a step in your CI workflow.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="random"/></entry><entry><title>Vimwiki Website Deployment using Git Hooks</title><link href="https://blog.jnduli.co.ke/vimwiki-website-deployment-using-git-hooks.html" rel="alternate"/><published>2019-06-09T00:00:00+03:00</published><updated>2019-06-09T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-06-09:/vimwiki-website-deployment-using-git-hooks.html</id><summary type="html">&lt;p&gt;I use vimwiki to keep a track of my notes. This includes book summaries,
linux commands, recipes and miscellanous content. It's an amazing vim
plugin that provides easy access and navigation to the content. This
however works well only within vim.&lt;/p&gt;
&lt;p&gt;I occasionally need to access these notes outside vim …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I use vimwiki to keep a track of my notes. This includes book summaries,
linux commands, recipes and miscellanous content. It's an amazing vim
plugin that provides easy access and navigation to the content. This
however works well only within vim.&lt;/p&gt;
&lt;p&gt;I occasionally need to access these notes outside vim and my laptop. One
of the solutions for this is to have the content online as html, thus I
can easily access this using any device that has a browser. Vimwiki
supports note to html conversion using &lt;cite&gt;VimwikiAll2HTML&lt;/cite&gt; command.
Running that command in vim will generate a website on the specified
directory.&lt;/p&gt;
&lt;p&gt;I configured vimwiki to generate the website at my preferred location using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;g:vimwiki_list&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;~/vimwiki&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;path_html&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;~/vimwiki/public_html&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I also needed a means of syncing the website with my notes. So anytime I
add a new note or change some content, the website would also get
updated with this. To solve this, I used &lt;cite&gt;git hooks&lt;/cite&gt; (I version control my
notes). I added a &lt;cite&gt;post-commit&lt;/cite&gt; hook, which would build the html content
using vim and upload it to the server.&lt;/p&gt;
&lt;p&gt;To generate the html content:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;vim&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;:VimwikiIndex&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;:VimwikiAll2HTML&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;qa!&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;/dev/tty
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;cite&gt;-R&lt;/cite&gt; option ensures the file is open in &lt;cite&gt;ReadOnly&lt;/cite&gt; mode. This is
because the &lt;cite&gt;index wiki&lt;/cite&gt; file might be open on another vim instance
while this command runs.&lt;/p&gt;
&lt;p&gt;The &lt;cite&gt;VimwikiIndex&lt;/cite&gt; command opens up the first wiki file in the
&lt;cite&gt;vimwiki_list&lt;/cite&gt; variable.&lt;/p&gt;
&lt;p&gt;The &lt;cite&gt;VimwikiAll2HTML&lt;/cite&gt; command will generate the html files.&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;qa!&lt;/cite&gt; exits vim.&lt;/p&gt;
&lt;p&gt;Running this command from &lt;cite&gt;post-commit&lt;/cite&gt; hook raised a warning, resulting
in the output being mungled. To fix this, &lt;cite&gt;&amp;lt; /dev/tty&lt;/cite&gt; is appended to
the command. This discussion can be found &lt;a class="reference external" href="https://stackoverflow.com/questions/16517568/vim-exec-command-in-command-line-and-vim-warning-input-is-not-from-a-terminal"&gt;here on stackoverflow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To upload the files to my server, I use &lt;cite&gt;rsync&lt;/cite&gt;. Here's the command
used:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rsync&lt;span class="w"&gt; &lt;/span&gt;-rav&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ssh -p 1233&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;public_html/&lt;span class="w"&gt; &lt;/span&gt;username@example.co.ke:/home/username/vimwiki
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Combined, the &lt;cite&gt;post-commit&lt;/cite&gt; file contains:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;

vim&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;:VimwikiIndex&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;:VimwikiAll2HTML&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;qa!&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;/dev/tty
rsync&lt;span class="w"&gt; &lt;/span&gt;-rav&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ssh -p 1233&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;public_html/&lt;span class="w"&gt; &lt;/span&gt;username@example.co.ke:/home/username/vimwiki
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now every time I commit to the repo, the online version of my wiki is
also updated automatically. Serving this directory is just a matter of
setting up nginx properly (or the webserver being used). For security, I
use &lt;cite&gt;.htpasswd&lt;/cite&gt; files using the guide found &lt;a class="reference external" href="https://www.digitalocean.com/community/tutorials/how-to-set-up-password-authentication-with-nginx-on-ubuntu-14-04"&gt;here&lt;/a&gt;.&lt;/p&gt;
</content><category term="Computer"/><category term="projects"/><category term="vim"/></entry><entry><title>PC Assembly and Motorola C Plus Fix</title><link href="https://blog.jnduli.co.ke/pc-assembly-errors-and-motorola-c-plus-fix.html" rel="alternate"/><published>2019-05-26T00:00:00+03:00</published><updated>2019-05-26T00:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-05-26:/pc-assembly-errors-and-motorola-c-plus-fix.html</id><summary type="html">&lt;p&gt;I assembled my first PC this month. It took me a full Saturday for this,
and I blame it on the case I got. I cheaped out on it, and ended up
taking a lot of time setting things properly inside it. Here is the &lt;a class="reference external" href="https://pcpartpicker.com/user/jnduli/saved/#view=CMgBZL"&gt;build&lt;/a&gt;. Some of the
mistakes …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I assembled my first PC this month. It took me a full Saturday for this,
and I blame it on the case I got. I cheaped out on it, and ended up
taking a lot of time setting things properly inside it. Here is the &lt;a class="reference external" href="https://pcpartpicker.com/user/jnduli/saved/#view=CMgBZL"&gt;build&lt;/a&gt;. Some of the
mistakes I made include:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Cheaping out on the case. This made it really difficult to add
various parts. I also gave up on cable management.&lt;/li&gt;
&lt;li&gt;Bought too many fans. The case only supports two fans (of which it
comes with both).&lt;/li&gt;
&lt;li&gt;I didn't have a proper monitor that capitalizes on the PC power.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I really like the build though, and I'm using it to play games and for
some machine learning. I also got to find out that steam support on linux is
really great (the PC runs linux btw).&lt;/p&gt;
&lt;p&gt;I also did my first screen replacement this month. I own a Motorola Moto
C Plus, and its touch screen had stopped working completely. I ordered one
off ebay, and got around to replacing it. The process was
surprisingly easy. For tools, I was lucky to have everything I needed,
which was a screw driver set, tweezers and a heat gun.&lt;/p&gt;
&lt;p&gt;Here is the video guide I followed:&lt;/p&gt;
&lt;iframe width="690" height="388" src="https://www.youtube.com/embed/AkOWL2akBtk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;</content><category term="Random"/><category term="projects"/></entry><entry><title>Huion 420 driver setup</title><link href="https://blog.jnduli.co.ke/huion-420-driver-setup.html" rel="alternate"/><published>2019-04-27T19:00:00+03:00</published><updated>2019-04-27T19:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-04-27:/huion-420-driver-setup.html</id><summary type="html">&lt;p&gt;I bought the Huion 420 because I wanted to experiment with graphics
tablet and drawing on linux. I chose this primarily because of its cost.
Out of the box, the device worked on my archlinux setup, however it
behaved more like a mouse, with pressure sensitivity not detected. I did …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I bought the Huion 420 because I wanted to experiment with graphics
tablet and drawing on linux. I chose this primarily because of its cost.
Out of the box, the device worked on my archlinux setup, however it
behaved more like a mouse, with pressure sensitivity not detected. I did
some research and this is how I fixed this.&lt;/p&gt;
&lt;p&gt;I first had to install the digimend drivers. To do that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;linux-headers
yay&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;digimend-kernel-drivers-dkms-git
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I had to unload previous versions of the drivers using modprobe.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;modprobe&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;hid-kye&lt;span class="w"&gt; &lt;/span&gt;hid-uclogic&lt;span class="w"&gt; &lt;/span&gt;hid-polostar&lt;span class="w"&gt; &lt;/span&gt;hid-viewsonic
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The default settings were not to my liking and I found out there exists
a tool that configures wacom tablets that can work with other models. It
is a hit or miss whether this tool will work with your tablet, but in my
case, it worked perfectly. To install the tool:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;xf86-input-wacom
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then set up this file in xorg i.e. in my case, I created the file
&lt;cite&gt;/etc/X11/xorg.conf.d/52-tablet.conf&lt;/cite&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Section&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;InputClass&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Identifier&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Huion on wacom&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;MatchProduct&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HUION&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;MatchDevicePath&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dev/input/event*&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Driver&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;wacom&amp;quot;&lt;/span&gt;
EndSection
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To check if this worked, I restarted the laptop and ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;xsetwacom&lt;span class="w"&gt; &lt;/span&gt;--list
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Seeing the contents below confirmed that the configuration had worked:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;HUION&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;420&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Pad&lt;span class="w"&gt; &lt;/span&gt;pad&lt;span class="w"&gt;                       &lt;/span&gt;id:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;21&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;type:&lt;span class="w"&gt; &lt;/span&gt;PAD
HUION&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;420&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Pen&lt;span class="w"&gt; &lt;/span&gt;stylus&lt;span class="w"&gt;                    &lt;/span&gt;id:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;22&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;type:&lt;span class="w"&gt; &lt;/span&gt;STYLUS
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To edit the pressure of the tool, I used gimp. For this go to
&lt;cite&gt;Edit&amp;gt;Input Devices&lt;/cite&gt;, select the &lt;cite&gt;HUION 420 Pen stylus&lt;/cite&gt; and set &lt;cite&gt;mode&lt;/cite&gt;
to &lt;cite&gt;Screen&lt;/cite&gt;. The pressure was then be detected in gimp.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/DIGImend/digimend-kernel-drivers"&gt;https://github.com/DIGImend/digimend-kernel-drivers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://wiki.archlinux.org/index.php/Wacom_tablet"&gt;https://wiki.archlinux.org/index.php/Wacom_tablet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Computer"/><category term="linux"/><category term="product"/><category term="review"/></entry><entry><title>Python Generators</title><link href="https://blog.jnduli.co.ke/python-generators.html" rel="alternate"/><published>2019-04-20T14:30:00+03:00</published><updated>2019-04-20T14:30:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-04-20:/python-generators.html</id><summary type="html">&lt;p&gt;Generators are functions that behave like iterators, thus can be used in
for loops. For example, a generator that produces even numbers will look
like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;even_numbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upperlimit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;upperlimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Generators are also created using a syntax similar to list
comprehension:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;even_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n …&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Generators are functions that behave like iterators, thus can be used in
for loops. For example, a generator that produces even numbers will look
like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;even_numbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upperlimit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;upperlimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Generators are also created using a syntax similar to list
comprehension:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;even_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Generators are lazy loading, which means that a value is generated only
when it's needed. This can best be observed in the even_numbers function
above. It is used as shown below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;even_numbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Prints 0&lt;/span&gt;
&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Prints 2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The computation for the next item only occurs when next is called. After
yield, the function pauses, waiting for the next command to be called.
The advantage of this is that it improves memory performance, since the
values are only generated when needed, versus having them in an list.
this can be shown in the example below, where the list is orders of
magnitude larger than the generator.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Outputs 4290016 bytes&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Outputs 120 bytes&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another advantage is that generators do not make an assumption on the
data structure one wants. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;even_numbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;even_numbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As seen above, it is really simple to get different data structures when
using generators.&lt;/p&gt;
&lt;p&gt;Communication can be done with generators using &lt;cite&gt;send&lt;/cite&gt;. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;even_numbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;new_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_max&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;upper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_max&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the above example, the upper limit can be changed while iterating
through the generator. This is shown below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;even&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;even_numbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;even&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;even&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;cite&gt;generator.send()&lt;/cite&gt; works similar to next, in that it resumes the
generator. This means that at it also produces the next result in the
iteration. This is why the result of the &lt;cite&gt;even.send(10)&lt;/cite&gt; is also printed
out, otherwise the above operation would skip printing &lt;cite&gt;6&lt;/cite&gt;.&lt;/p&gt;
</content><category term="Computer"/><category term="programming"/></entry><entry><title>Ansible and SSH Port</title><link href="https://blog.jnduli.co.ke/ansible-and-ssh-ports.html" rel="alternate"/><published>2019-04-16T09:00:00+03:00</published><updated>2019-04-16T09:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-04-16:/ansible-and-ssh-ports.html</id><summary type="html">&lt;p&gt;Hackers and bots try to log into servers all the time. They do this by
trying random ssh logins into your server. A deterrent to this is to
disable the default ssh port and set it to something else. Also, disable
root login as this is the most common user …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hackers and bots try to log into servers all the time. They do this by
trying random ssh logins into your server. A deterrent to this is to
disable the default ssh port and set it to something else. Also, disable
root login as this is the most common user attempt I've seen on my
server.&lt;/p&gt;
&lt;p&gt;To disable the port globally, just edit the &lt;cite&gt;/etc/ssh/sshd_config&lt;/cite&gt; file
to have the line shown below (the &lt;cite&gt;1234&lt;/cite&gt; should be any number you wish below 65535):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1234&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After disabling port 22, ansible did not work as expected because if
uses this port by default. To fix this, the url used
with my playbooks was changed from the terminal, as shown below.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;example.com:1234&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;guest&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;playbook.yml
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Other alternatives I found while researching this include:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;Editting every role to include the port required&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;Example for port change&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;set_fact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;ansible_port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;1234&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Setting the port directly with &lt;cite&gt;ansible_ssh_port&lt;/cite&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;playbook.yml&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ansible_ssh_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1234&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;ol class="arabic" start="3"&gt;
&lt;li&gt;&lt;p class="first"&gt;Using ansibles inventory hosts and setting the port explicitly. Other
inventory formats can be found in the &lt;a class="reference external" href="https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#hosts-and-groups"&gt;ansible docs&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;webservers&lt;span class="o"&gt;]&lt;/span&gt;
example.com:1234
&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content><category term="Computer"/><category term="programming"/><category term="server"/></entry><entry><title>Pagination: Review of Django's and Pelican's Implementation</title><link href="https://blog.jnduli.co.ke/pagination-review-of-django-pelican-implementation.html" rel="alternate"/><published>2019-03-09T17:30:00+03:00</published><updated>2019-03-09T17:30:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-03-09:/pagination-review-of-django-pelican-implementation.html</id><summary type="html">&lt;p&gt;Pagination is the process of dividing up a document into discrete pages
(&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Pagination"&gt;wikipedia&lt;/a&gt;). Django and
Pelican have similar pagination implementations. This boils down to
having a class that has accepts a sliceable object as one of its params,
and returns a page containing list of items depending on number of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Pagination is the process of dividing up a document into discrete pages
(&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Pagination"&gt;wikipedia&lt;/a&gt;). Django and
Pelican have similar pagination implementations. This boils down to
having a class that has accepts a sliceable object as one of its params,
and returns a page containing list of items depending on number of items
per page. The django &lt;a class="reference external" href="https://docs.djangoproject.com/en/2.1/topics/pagination/#required-arguments"&gt;paginator docs&lt;/a&gt;
describe the object list as a list, tuple, QuerySet, or other sliceable
object with a count() or __len__() method.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;paginator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Paginator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To get the contents of a particular page one calls the get_page method:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;paginator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What this does is to first check if the number provided is valid using
the validate_number method. A number is valid if its an integer, it's
greater than 0 and is less that the total number of pages in the
paginator (if the alloy_empty_first_page parameter was set to True, 1
will be valid even if the total number of pages is 0).&lt;/p&gt;
&lt;p&gt;If the number was valid the page method is called. This creates the
required start and end slices i.e.`start:end` on the object list, and
returns a Page object that only contains these elements.&lt;/p&gt;
&lt;p&gt;The code below shows some boiler plate that can achieve this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Paginator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;allow_empty_first_page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;per_page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orphans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orphans&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allow_empty_first_page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allow_empty_first_page&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;validate_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Make sure number is integer, greater than 1 and less than&lt;/span&gt;
        &lt;span class="c1"&gt;# the total number of pages&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# if number is valid, returns a page object.&lt;/span&gt;
        &lt;span class="c1"&gt;# This is done by getting range of items required&lt;/span&gt;
        &lt;span class="c1"&gt;# e.g. 11:20, and returning an object that one can iterate&lt;/span&gt;
        &lt;span class="c1"&gt;# through (called a Page object)&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;num_pages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="c1"&gt;# Returns the total number of pages&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="c1"&gt;# Returns total number of objects&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To loop over the page object with a for, the Page class implements the
__getitem__ for this. Pelican's implementation does not have this method
though. It also has some useful methods like:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;cite&gt;has_next&lt;/cite&gt;&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;has_previous&lt;/cite&gt;&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;has_other_pages&lt;/cite&gt;&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;next_page_number&lt;/cite&gt;&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;previous_page_number&lt;/cite&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these one can effectively get the contents of a page by looping
through the paginator (in django only) and have various logic on which
page numbers to display.&lt;/p&gt;
&lt;p&gt;The example provided in the &lt;a class="reference external" href="https://docs.djangoproject.com/en/2.1/topics/pagination/#using-paginator-in-a-view"&gt;django docs here&lt;/a&gt;
shows a really good usage of the various methods.&lt;/p&gt;
</content><category term="Computer"/><category term="programming"/></entry><entry><title>Django's Cached Property</title><link href="https://blog.jnduli.co.ke/django-cached-property-explanation.html" rel="alternate"/><published>2019-02-28T14:30:00+03:00</published><updated>2019-02-28T14:30:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-02-28:/django-cached-property-explanation.html</id><summary type="html">&lt;p&gt;I've been trying to understand how django's decorator &lt;cite&gt;&amp;#64;cached_property&lt;/cite&gt;
works. Here is the class definition (&lt;a class="reference external" href="https://github.com/django/django/blob/2.1/django/utils/functional.py"&gt;original source&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Got from django code base&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;cached_property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    Decorator that converts a method with a single self argument into a&lt;/span&gt;
&lt;span class="sd"&gt;    property cached on the instance.&lt;/span&gt;
&lt;span class="sd"&gt;    Optional ``name`` argument allows you to make cached properties …&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I've been trying to understand how django's decorator &lt;cite&gt;&amp;#64;cached_property&lt;/cite&gt;
works. Here is the class definition (&lt;a class="reference external" href="https://github.com/django/django/blob/2.1/django/utils/functional.py"&gt;original source&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Got from django code base&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;cached_property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    Decorator that converts a method with a single self argument into a&lt;/span&gt;
&lt;span class="sd"&gt;    property cached on the instance.&lt;/span&gt;
&lt;span class="sd"&gt;    Optional ``name`` argument allows you to make cached properties of other&lt;/span&gt;
&lt;span class="sd"&gt;    methods. (e.g.  url = cached_property(get_absolute_url, name=&amp;#39;url&amp;#39;) )&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__doc__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__doc__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__get__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;        Call the function and put the return value in instance.__dict__ so that&lt;/span&gt;
&lt;span class="sd"&gt;        subsequent attribute access on the instance returns the cached value&lt;/span&gt;
&lt;span class="sd"&gt;        instead of calling cached_property.__get__().&lt;/span&gt;
&lt;span class="sd"&gt;        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will be used in a class as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

   &lt;span class="nd"&gt;@cached_property&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="c1"&gt;# Prints 4. Performs computation&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="c1"&gt;# Prints 4. Uses the cached value&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When the instance &lt;cite&gt;d&lt;/cite&gt; of &lt;cite&gt;Double&lt;/cite&gt; first accesses the &lt;cite&gt;square&lt;/cite&gt; property,
the &lt;cite&gt;__get__&lt;/cite&gt; from the &lt;cite&gt;cached_property&lt;/cite&gt; class is called. This method
receives the instance &lt;cite&gt;d&lt;/cite&gt; as one of its parameters. It then calls the
actual function and stores the result in the instance's
&lt;cite&gt;__dict__[square]&lt;/cite&gt; variable. The next time the &lt;cite&gt;square&lt;/cite&gt; property is
accessed, it picks up the appropriate value from its &lt;cite&gt;__dict__&lt;/cite&gt; and the
function is not called. This is because &lt;cite&gt;d&lt;/cite&gt; has a lookup chain starting
from &lt;cite&gt;b.__dict__['square']&lt;/cite&gt; as explained &lt;a class="reference external" href="https://docs.python.org/3.7/howto/descriptor.html#id3"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However should the object be changed, for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="c1"&gt;# Prints 4&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;the &lt;cite&gt;square&lt;/cite&gt; still prints 4 instead of 9. This is because the &lt;cite&gt;square&lt;/cite&gt;
method is still accessing the cached value. To update this, the
&lt;cite&gt;__dict__[square]&lt;/cite&gt; parameter has to be cleared before.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;square&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="c1"&gt;# Now prints 9&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Clearing this will force a recomputation of the square variable.
However, it's really easy to skip this, so I think the &lt;cite&gt;cached_property&lt;/cite&gt;
should be used where the objects parameters are not expected to change.&lt;/p&gt;
</content><category term="Computer"/><category term="programming"/></entry><entry><title>Courage To Be Disliked: A Review</title><link href="https://blog.jnduli.co.ke/courage-to-be-disliked-a-review.html" rel="alternate"/><published>2019-02-13T16:20:00+03:00</published><updated>2019-02-13T16:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-02-13:/courage-to-be-disliked-a-review.html</id><summary type="html">&lt;p&gt;Courage to be disliked is a book that explains Adlerian psychology. It
does so in the form of a dialog, between a student and a master. Here
are the various ideas I got from reading the book:&lt;/p&gt;
&lt;div class="section" id="etiology-vs-teleology"&gt;
&lt;h2&gt;Etiology vs Teleology&lt;/h2&gt;
&lt;p&gt;Etiology is when someone focuses on the past, and uses …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Courage to be disliked is a book that explains Adlerian psychology. It
does so in the form of a dialog, between a student and a master. Here
are the various ideas I got from reading the book:&lt;/p&gt;
&lt;div class="section" id="etiology-vs-teleology"&gt;
&lt;h2&gt;Etiology vs Teleology&lt;/h2&gt;
&lt;p&gt;Etiology is when someone focuses on the past, and uses past experiences
and events to explain what has currently happened. The text is heavily
against this, since it provides an easy way out of various problems that
occur in life. The book however emphasizes on teleology, which is where
one focuses on the now, and tries to find out why various things have
happened. A good example of this is when one goes to the doctor, who
doesn't try to figure out what past event caused some disease, but
rather focusses on the current symptoms and treating the current
ailment.&lt;/p&gt;
&lt;p&gt;The biggest problem with etiology however, is that it can lead to self
determinism. This is where one believes that how their life
progresses has already been determined by events in the past, and that
nothing can change this.&lt;/p&gt;
&lt;p&gt;Teleology also provides a new insight into various events and reactions.
For example, people tend to blame some reactions on their anger, as
though it was a separate entity from themselves. However, anger is a
tool that can be used to achieve some goal. A good example of this is
when a mother is angrily scolding their child. If the mother receives a
phone call, she'll put the anger away and calmly receive the call.
Afterwards, she becomes angry again and continues to scold the child.
This shows that the mother is using anger as a tool against her child.&lt;/p&gt;
&lt;p&gt;Teleology also provides a means of understanding why changing one's
lifestyle seems difficult. People tend to remain in their lifestyle
because it's comfortable and easy to predict. Lifestyles may also
provide good explanations for some decisions one has made. For example,
someone who dreams of becoming a novelist yet their job keeps them too
busy. A teleological explanation of why the novelist doesn't quit would
be that s/he is using the job (instead of quiting and focussing on the
novel) because he is actually afraid of criticism of his novel or that
s/he may produce inferior writing. Later on in their lives, they will
use the reason of old age for this too.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="weakness-and-strength"&gt;
&lt;h2&gt;Weakness and Strength&lt;/h2&gt;
&lt;p&gt;Key emotions that tend to help people become better are the feeling of
inferiority and the pursuit of superiority. They help support one's
striving for growth. However, when these feelings become a hindrance,
they develop into complexes. The inferiority complex occurs when one
uses their feelings of inferiority as an excuse in life.  For example,
one can claim that they cannot be successful because they are
uneducated, and therefore won't try to overcome this obstacle. The
superiority complex is whereby one has the feeling of inferiority but
doesn't have the strength to strive for growth. They compensate for this
by associating with people or things they feel are superior e.g. some
brands of clothes or some celebrities.&lt;/p&gt;
&lt;p&gt;Weakness can make one strong and powerful. For example, the baby can
control the parents because it is weak. Some people tend to cling to
their weaknesses so as to get some hold of people. If someone tries to
help them overcome their weakness, they use the fact that the other
party cannot possible understand their feelings as a deterrent.
However, in doing so, they become slaves to their weaknesses and end up
unable to survive without this.&lt;/p&gt;
&lt;p&gt;Going through life as though it is a competition is another form of
weakness. This is because if competition is at the core of one's
interpersonal relationships, one will start viewing people as enemies
who must not be underestimated. This makes the world a scary place to
live in.&lt;/p&gt;
&lt;p&gt;Also when having a discussion with someone, the moment it becomes a
power struggle, one should step down. This is because the conversation
has derailed from that of providing information/opinion to that of
winner and losers. Also, avoid criticizing the other party just because
you think you're right, otherwise the conversation will degenerate into
a power struggle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="life-tasks"&gt;
&lt;h2&gt;Life Tasks&lt;/h2&gt;
&lt;p&gt;Another interesting concept introduced in the book is that of tasks. An
individual has three main classifications of tasks:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Task of friendship&lt;/li&gt;
&lt;li&gt;Task of work&lt;/li&gt;
&lt;li&gt;Task of love&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Separation of tasks is whereby one decides to what point one's own tasks
go, and from which point the tasks become another person's. Once this is
done, one should do their own tasks to the best of their ability, and
only lend a hand to others when needed. However, one should be careful
not to encroach on another person's territory. To help with this, one
needs a good way of figuring out ownership of a task. An indication of
this is who will eventually benefit if the task is done.&lt;/p&gt;
&lt;p&gt;In interpersonal relationships, it is the individual's task to believe
in the other party. How the other party behaves with regard to said
belief is not the individual's task. So if the other party takes
advantage of you, that is still their task. If one feels the
relationship is becoming problematic, it should be severed (which is the
individual's task).&lt;/p&gt;
&lt;p&gt;It is also one's task to live one's life the best way one believe in. The
judgement passed by people about one's life is not one's task. This
therefore means one is free to do as one pleases. In fact, freedom can
be defined as being disliked by other people.  This is because being
disliked by others is proof that one is living life as one would please,
not trying to satisfy others.&lt;/p&gt;
&lt;p&gt;Furthermore, if a task is beyond one's capability, one needs to accept
this and move forward in doing what one can do (self acceptance) thus
one avoids lying to oneself. This is counter to self affirmation, where
one uses phrases like 'I can do it', when something is cleary beyond
one's ability. A good example for this is in exams, where if someone
fails they will either say 'I was unlucky this time' (self affirmation)
or accept what they got and try to improve for the next exam (self
acceptance).&lt;/p&gt;
&lt;p&gt;People try to be special because they cannot accept their normal selves.
They therefore equate being normal with being incapabale. However, with
self acceptance, once accepts their ordinary selves. One should then
have the courage to be normal.&lt;/p&gt;
&lt;p&gt;The problem with aiming to be special (having lofty goals) is that one
views life like climbing a mountain, where if they do not reach the
peak, they have not reached their &amp;quot;real life&amp;quot;. This means they are not
living in the present. The greatest life lie of all is in fact to not
live here and now. A better alternative is to view life as a series of
moments, without a destination. This way, one ends up living their &amp;quot;real
life&amp;quot; every day, every hour and every minute.&lt;/p&gt;
&lt;p&gt;&amp;quot;Life in general has no meaning. Whatever meaning life has must be
assigned to it by the individual.&amp;quot;&lt;/p&gt;
&lt;/div&gt;
</content><category term="Random"/><category term="book"/></entry><entry><title>Sway Window Manager</title><link href="https://blog.jnduli.co.ke/sway-window-manager.html" rel="alternate"/><published>2019-01-12T08:00:00+03:00</published><updated>2019-01-12T08:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2019-01-12:/sway-window-manager.html</id><summary type="html">&lt;p&gt;Wayland is a display server that should work as a replacement for X.
I've been thinking of trying it out for some time now. Detailed
information about wayland and its history can be found &lt;a class="reference external" href="https://www.linux.com/news/what-why-and-how-wayland-and-weston-linux"&gt;in this article&lt;/a&gt;. The
differences between xorg and wayland can be found &lt;a class="reference external" href="https://www.secjuice.com/wayland-vs-xorg/"&gt;here&lt;/a&gt; or in this …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Wayland is a display server that should work as a replacement for X.
I've been thinking of trying it out for some time now. Detailed
information about wayland and its history can be found &lt;a class="reference external" href="https://www.linux.com/news/what-why-and-how-wayland-and-weston-linux"&gt;in this article&lt;/a&gt;. The
differences between xorg and wayland can be found &lt;a class="reference external" href="https://www.secjuice.com/wayland-vs-xorg/"&gt;here&lt;/a&gt; or in this &lt;a class="reference external" href="https://askubuntu.com/questions/11537/why-is-wayland-better"&gt;thread&lt;/a&gt;. It
seems to me the biggest problem with wayland is that it is not network
aware (although I haven't used this feature yet in xorg preferring using
vnc servers instead) and that some programs will not work with it (for
example, redshift).&lt;/p&gt;
&lt;p&gt;However, the biggest block for me was that my i3 workflow had been
ingrained in my muscle memory and I did not want to lose this. Luckily,
I found &lt;a class="reference external" href="https://swaywm.org/"&gt;sway&lt;/a&gt;. Surprisingly, it worked with most
of my i3 configuration, only having to make changes to custom mapping
applications that were x based e.g. feh.&lt;/p&gt;
&lt;p&gt;To set sway up, I decided to avoid the version used in pacman, because
it seemed to be too old. I went with bleeding edge sway and set it up
using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;yay&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;wlroots-git&lt;span class="w"&gt; &lt;/span&gt;sway-git
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this I get the latest version plus all its improvements. The
problem though, is that sway sometimes fails to start after a system
update. To fix this, I just start up i3 and run the above command again.&lt;/p&gt;
&lt;p&gt;This might be subjective, but I found the colours in swaywm when I first
used it to be better and brighter. This is something I had always wanted
to figure out how to fix in i3, but never got around to doing this.&lt;/p&gt;
&lt;p&gt;I also felt that out of the box, it had better support for my touchpad.
It did not have a lot of ghost touches, random scrolling behaviour, etc.
which in i3, I have to spend a lot of time tweaking and configuring the
touchpad settings. In sway, these are the only configurations I had to
enable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;input&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1267:12328:ELAN1300:00_04F3:3028_Touchpad&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;dwt&lt;span class="w"&gt; &lt;/span&gt;enabled
&lt;span class="w"&gt;    &lt;/span&gt;tap&lt;span class="w"&gt; &lt;/span&gt;enabled
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The problems I have with sway are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;I haven't found a way to set up a floating terminal window. I have
defaulted to using a floating window usint this configuration:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+F12&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xfce4-terminal&lt;span class="w"&gt; &lt;/span&gt;--drop-down&lt;span class="w"&gt; &lt;/span&gt;--title&lt;span class="o"&gt;=&lt;/span&gt;dropdown
for_window&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dropdown&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;floating&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Switching between keyboard layouts is tricky. The options I've got
involve restarting sway with the new keyboard layout I intend to use,
for example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;XKB_DEFAULT_LAYOUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;XKB_DEFAULT_VARIANT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;qwerty&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sway
&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;When connecting an external monitor to my laptop, I expect it to be on
the right of the laptop screen. However, sway defaults with it on the
left. To fix this, I set up both screens and their index as shown
below:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;eDP-1&lt;span class="w"&gt; &lt;/span&gt;resolution&lt;span class="w"&gt; &lt;/span&gt;1920x1080&lt;span class="w"&gt; &lt;/span&gt;position&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,0
output&lt;span class="w"&gt; &lt;/span&gt;HDMI-A-1&lt;span class="w"&gt; &lt;/span&gt;resolution&lt;span class="w"&gt; &lt;/span&gt;1280x1024&lt;span class="w"&gt; &lt;/span&gt;position&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1920&lt;/span&gt;,0
&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Computer"/><category term="window-managers"/></entry><entry><title>Summary of 2018</title><link href="https://blog.jnduli.co.ke/summary-2018.html" rel="alternate"/><published>2018-12-31T19:00:00+03:00</published><updated>2018-12-31T19:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-12-31:/summary-2018.html</id><summary type="html">&lt;p&gt;This year has been meh for me ;( The highlights for the year include:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Completing course work for my masters class&lt;/li&gt;
&lt;li&gt;Starting research on Renewable Energy Systems and how best to size
them and control this system.&lt;/li&gt;
&lt;li&gt;Active participation in various communities I managed to join
especially Urban Perspective and NaiLUG …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;This year has been meh for me ;( The highlights for the year include:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Completing course work for my masters class&lt;/li&gt;
&lt;li&gt;Starting research on Renewable Energy Systems and how best to size
them and control this system.&lt;/li&gt;
&lt;li&gt;Active participation in various communities I managed to join
especially Urban Perspective and NaiLUG.&lt;/li&gt;
&lt;li&gt;Achieved most of the fitness goals I had intended to achieve at the start of
the year. Key amongst these is jogging at least 3 times a week.&lt;/li&gt;
&lt;li&gt;I also started doing some investments this year, mostly passive. Part
of my investment strategy had been in agribusiness (active
invesetment) this year, but things did not go too well of that front.
At least I achieved some level of financial literacy this year, and
have a better strategy for the oncoming year.&lt;/li&gt;
&lt;li&gt;I attended my first _ruracio_ this year. It was a unique experience
merging traditional culture with modern expectations.&lt;/li&gt;
&lt;li&gt;I had my first trip outside Nairobi. I managed to visit Naivasha and
Elementaita on an unofficial class trip. I realised I like to travel
(hopefully this will remain true) and will endeavour to visit more
places next year.&lt;/li&gt;
&lt;li&gt;Managed to sort out internet at home. This by far had the most impact
on my life this year. Having to use the internet without limits (as
had been initially the case with the bundles options I was having with
Telkom) was really refreshing. I could now experiment more, play with
more technologies and not have to think about effects of data on my
wallet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also managed to read some really interesting books this year, like
Deep Work and Lauren Ipsum. I didn't get to my goal of 20 books and I'm
blaming this on my loose concentration. This is whereby I'll leave a
half finished book if and when I get something more interesting. I hope
to improve on this next year.&lt;/p&gt;
</content><category term="Random"/><category term="random"/></entry><entry><title>Fixing Small Fonts on My Laptop</title><link href="https://blog.jnduli.co.ke/fixing-small-fonts-on-my-laptop.html" rel="alternate"/><published>2018-09-17T16:20:00+03:00</published><updated>2018-09-17T16:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-09-17:/fixing-small-fonts-on-my-laptop.html</id><summary type="html">&lt;p&gt;I have been having this problem with my laptop where the
fonts seem too small. To fix this, I first had to check out my
laptop's screen configurations:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;xrandr
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Part of the output of this command is shown below. As can be seen it shows that my laptop screen is …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have been having this problem with my laptop where the
fonts seem too small. To fix this, I first had to check out my
laptop's screen configurations:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;xrandr
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Part of the output of this command is shown below. As can be seen it shows that my laptop screen is 'eDP1' and has dimensions of 290mm by 170mm.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Screen&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;minimum&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;current&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1920&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1080&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;maximum&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32767&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32767&lt;/span&gt;
eDP1&lt;span class="w"&gt; &lt;/span&gt;connected&lt;span class="w"&gt; &lt;/span&gt;primary&lt;span class="w"&gt; &lt;/span&gt;1920x1080+0+0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;left&lt;span class="w"&gt; &lt;/span&gt;inverted&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;290mm&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;170mm
&lt;span class="w"&gt;   &lt;/span&gt;1920x1080&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;.05*+&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;59&lt;/span&gt;.93
&lt;span class="w"&gt;   &lt;/span&gt;1680x1050&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;59&lt;/span&gt;.88
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another command that can find screen information is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;xdpyinfo&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-B2&lt;span class="w"&gt; &lt;/span&gt;resolution
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This command shows different screen dimensions. Its output is
shown below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;screen&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;dimensions:&lt;span class="w"&gt;    &lt;/span&gt;1920x1080&lt;span class="w"&gt; &lt;/span&gt;pixels&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;508x285&lt;span class="w"&gt; &lt;/span&gt;millimeters&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;resolution:&lt;span class="w"&gt;    &lt;/span&gt;96x96&lt;span class="w"&gt; &lt;/span&gt;dots&lt;span class="w"&gt; &lt;/span&gt;per&lt;span class="w"&gt; &lt;/span&gt;inch
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is some discrepancy somewhere. To fix this, I had to create
a monitor configuration file in
&lt;cite&gt;/etc/X11/xorg.conf.d/90.monitor.conf&lt;/cite&gt; that contained the correct
screen dimensions. I got the screen dimensions by measuring them
with a tape measure. The contents of the file are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Section&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Monitor&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Identifier&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;eDP1&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;DisplaySize&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="m"&gt;290&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;170&lt;/span&gt;
EndSection
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then restarted i3 and my screen read comfortably. The
output from the xdpyinfo command shows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;screen&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;dimensions:&lt;span class="w"&gt;    &lt;/span&gt;1920x1080&lt;span class="w"&gt; &lt;/span&gt;pixels&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;290x170&lt;span class="w"&gt; &lt;/span&gt;millimeters&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;resolution:&lt;span class="w"&gt;    &lt;/span&gt;168x161&lt;span class="w"&gt; &lt;/span&gt;dots&lt;span class="w"&gt; &lt;/span&gt;per&lt;span class="w"&gt; &lt;/span&gt;inch
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I got most of the information to fix this &lt;a class="reference external" href="https://bbs.archlinux.org/viewtopic.php?id=195327"&gt;here&lt;/a&gt;.&lt;/p&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>Bluetooth Speakers Problems</title><link href="https://blog.jnduli.co.ke/fixing-bluetooth-speaker-problems.html" rel="alternate"/><published>2018-09-14T08:00:00+03:00</published><updated>2018-09-14T08:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-09-14:/fixing-bluetooth-speaker-problems.html</id><summary type="html">&lt;div class="section" id="connecting-to-device"&gt;
&lt;h2&gt;Connecting to Device&lt;/h2&gt;
&lt;p&gt;To connect to the bluetooth speakers, I use the bluetoothctl
commandline options. The following are commands I run for this to
work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;bluetooth.service
bluetoothctl
&lt;span class="c1"&gt;# Within the bluetoothctl environment&lt;/span&gt;
power&lt;span class="w"&gt; &lt;/span&gt;on
agent&lt;span class="w"&gt; &lt;/span&gt;on
default-agent
scan&lt;span class="w"&gt; &lt;/span&gt;on
pair&lt;span class="w"&gt; &lt;/span&gt;A4:A7:B5:22:E6:F5
connect …&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="connecting-to-device"&gt;
&lt;h2&gt;Connecting to Device&lt;/h2&gt;
&lt;p&gt;To connect to the bluetooth speakers, I use the bluetoothctl
commandline options. The following are commands I run for this to
work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;bluetooth.service
bluetoothctl
&lt;span class="c1"&gt;# Within the bluetoothctl environment&lt;/span&gt;
power&lt;span class="w"&gt; &lt;/span&gt;on
agent&lt;span class="w"&gt; &lt;/span&gt;on
default-agent
scan&lt;span class="w"&gt; &lt;/span&gt;on
pair&lt;span class="w"&gt; &lt;/span&gt;A4:A7:B5:22:E6:F5
connect&lt;span class="w"&gt; &lt;/span&gt;A4:A7:B5:22:E6:F5
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the device had been previously paired, I skip the pair step.&lt;/p&gt;
&lt;p&gt;Sometimes, my bluetooth speakers would fail to connect. To fix
this, I usually remove the item from the list of paired devices
and try to pair again before connecting.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;remove&lt;span class="w"&gt; &lt;/span&gt;A4:A7:B5:22:E6:F5
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another problem I've experience is whereby the device connects but
I can't hear sound from the speakers. To fix this, I first confirm
that the device is set up as an a2dp device in pavucontrol. If
this change has been made and there is still no sound, kill
pulseaudio.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pulseaudio&lt;span class="w"&gt; &lt;/span&gt;--kill
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="audacity"&gt;
&lt;h2&gt;Audacity&lt;/h2&gt;
&lt;p&gt;Audacity could not link up with my bluetooth speakers during
playback. However, the bluetooth speakers were visible from
pavucontrol and I could hear audio from them when using other
applications. To fix this, I had to install alsa-plugins.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;alsa-plugins
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once this was done, the options pulse were available in audio
recording and play back devices.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>Freeing up Space in my Linux Machine</title><link href="https://blog.jnduli.co.ke/freeing-up-space-in-linux-machine.html" rel="alternate"/><published>2018-08-26T16:00:00+03:00</published><updated>2018-08-26T16:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-08-26:/freeing-up-space-in-linux-machine.html</id><summary type="html">&lt;p&gt;I have a 256GB SSD on my laptop. This is rather constrained and I
occasionally end up with less than 10GB drive space. When this happens,
I have to figure out what is taking up all my space and fix this. This
prompts some form of search and cleaning up …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have a 256GB SSD on my laptop. This is rather constrained and I
occasionally end up with less than 10GB drive space. When this happens,
I have to figure out what is taking up all my space and fix this. This
prompts some form of search and cleaning up of the culprits. This
article lists the process and commands I usually run for this to
happen.&lt;/p&gt;
&lt;p&gt;To get a general feel of how much space I have:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;df&lt;span class="w"&gt; &lt;/span&gt;-h
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some sample output from this command is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Filesystem&lt;span class="w"&gt;      &lt;/span&gt;Size&lt;span class="w"&gt;  &lt;/span&gt;Used&lt;span class="w"&gt; &lt;/span&gt;Avail&lt;span class="w"&gt; &lt;/span&gt;Use%&lt;span class="w"&gt; &lt;/span&gt;Mounted&lt;span class="w"&gt; &lt;/span&gt;on
dev&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;/dev
run&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.4M&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;/run
/dev/sda5&lt;span class="w"&gt;       &lt;/span&gt;106G&lt;span class="w"&gt;   &lt;/span&gt;93G&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.4G&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;93&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;/
tmpfs&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;  &lt;/span&gt;132M&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.8G&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;/dev/shm
tmpfs&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;/sys/fs/cgroup
tmpfs&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.0K&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9G&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;/tmp
/dev/sda6&lt;span class="w"&gt;        &lt;/span&gt;41G&lt;span class="w"&gt;   &lt;/span&gt;20G&lt;span class="w"&gt;   &lt;/span&gt;21G&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;/run/media/silo
tmpfs&lt;span class="w"&gt;           &lt;/span&gt;787M&lt;span class="w"&gt;   &lt;/span&gt;20K&lt;span class="w"&gt;  &lt;/span&gt;787M&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;/run/user/1000
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This provides key information like what is the size of a partition and
how much space has been used up. The '-h' tag helps in making the sizes
easier to read.&lt;/p&gt;
&lt;p&gt;To list the various folders in root folder '/' and
their sizes, I use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;du&lt;span class="w"&gt; &lt;/span&gt;-sch&lt;span class="w"&gt; &lt;/span&gt;/*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sort&lt;span class="w"&gt; &lt;/span&gt;-h
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If permissions become a problem, you can run it with
sudo.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;11G&lt;span class="w"&gt;     &lt;/span&gt;/var
14G&lt;span class="w"&gt;     &lt;/span&gt;/opt
20G&lt;span class="w"&gt;     &lt;/span&gt;/run
33G&lt;span class="w"&gt;     &lt;/span&gt;/home
36G&lt;span class="w"&gt;     &lt;/span&gt;/usr
113G&lt;span class="w"&gt;    &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above shows part of the output of the above command. You can
change the folders as you try to figure out what is consuming
space.&lt;/p&gt;
&lt;p&gt;The &lt;cite&gt;du&lt;/cite&gt; command ignores files and folders that start with
a '.'. This can become troublesome because it will not give you
enough information about what is consuming space especially in the
home directory, which in my case is riddled with such. To fix that,
run this command instead:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;du&lt;span class="w"&gt; &lt;/span&gt;-sch&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="se"&gt;\!&lt;/span&gt;.&lt;span class="o"&gt;]&lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sort&lt;span class="w"&gt; &lt;/span&gt;-h
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will scan all folders including those that start with a '.'.
However it returns results of the current folder one is in. A more
generic one is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;du&lt;span class="w"&gt; &lt;/span&gt;-sch&lt;span class="w"&gt; &lt;/span&gt;/folder/path/&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="se"&gt;\!&lt;/span&gt;.&lt;span class="o"&gt;]&lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sort&lt;span class="w"&gt; &lt;/span&gt;-h
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;cite&gt;ls&lt;/cite&gt; command is another alternative for finding the sizes of files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;lah&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using the above commands, a general idea of where and how disk space is
used can be formed.&lt;/p&gt;
&lt;div class="section" id="cleaning-disk-space"&gt;
&lt;h2&gt;Cleaning Disk Space&lt;/h2&gt;
&lt;p&gt;Clearing up the cache of whatever installer I'm using is usually a good
place to start:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-Scc
sudo&lt;span class="w"&gt; &lt;/span&gt;yay&lt;span class="w"&gt; &lt;/span&gt;-Scc
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some installed packages take up a log of space. This command (found &lt;a class="reference external" href="https://www.commandlinefu.com/commands/view/7613/arch-linux-sort-installed-packages-by-size"&gt;here&lt;/a&gt;)
lists packages from the smallest to the largest.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-Qi&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Name\|Size\|Description&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;-d:&lt;span class="w"&gt; &lt;/span&gt;-f2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;paste&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;awk&lt;span class="w"&gt; &lt;/span&gt;-F&lt;span class="s1"&gt;&amp;#39;\t&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;BEGIN{ s[&amp;quot;MiB&amp;quot;]=1024; s[&amp;quot;KiB&amp;quot;]=1;} {split($3, a, &amp;quot; &amp;quot;); print a[1] * s[a[2]], &amp;quot;KiB&amp;quot;, $1}&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sort&lt;span class="w"&gt; &lt;/span&gt;-n
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can also remove orphans. To find them:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-Qtd
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Look through the list and remove what is not needed. To remove all
orphans:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-Rns&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-Qtdq&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Delete unnecessary files that are hogging up space. These can be found
using the &lt;cite&gt;dh&lt;/cite&gt; or &lt;cite&gt;ls&lt;/cite&gt; commands and deleted using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;file
rm&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;directory
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another huge disk space hog is my cache folder. I typically delete this
folder using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;./cache/*
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But if you want to be safe, you can delete only the files in that folder
that haven't been used in a year using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;find&lt;span class="w"&gt; &lt;/span&gt;~/.cache/&lt;span class="w"&gt; &lt;/span&gt;-type&lt;span class="w"&gt; &lt;/span&gt;f&lt;span class="w"&gt; &lt;/span&gt;-atime&lt;span class="w"&gt; &lt;/span&gt;+365&lt;span class="w"&gt; &lt;/span&gt;-delete
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I use docker a lot. So it tends to eat up a lot of disk space. The
following commands help me out here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;df&lt;span class="w"&gt; &lt;/span&gt;-v
sudo&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;prune
sudo&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;volume&lt;span class="w"&gt; &lt;/span&gt;prune
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Without the '-v' option, the command offers a summary of the
disk space used by docker.&lt;/p&gt;
&lt;p&gt;To deal with containers, I use the following commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;ps&lt;span class="w"&gt; &lt;/span&gt;-a
sudo&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;NAME
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first command will list all containers and the second command
deletes containers based on their name.&lt;/p&gt;
&lt;p&gt;To deal with images, I first list all the images with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;images&lt;span class="w"&gt; &lt;/span&gt;-a
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I usually like deleting the images with no tags. To that I run the
folloing command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;images&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&amp;lt;&lt;/span&gt;none&lt;span class="se"&gt;\&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;awk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{print $3}&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xargs&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;rmi
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this I can effectively remove files until I feel comfortable
with the remaining disk space.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>2018 So Far</title><link href="https://blog.jnduli.co.ke/2018-so-far.html" rel="alternate"/><published>2018-08-03T19:00:00+03:00</published><updated>2018-08-03T19:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-08-03:/2018-so-far.html</id><summary type="html">&lt;p&gt;This year so far has been tough.&lt;/p&gt;
&lt;p&gt;I thought I would have read around 10 books by now but I'm barely
half that mark. Most of the books are mostly fiction, but at least
I've got some variety this time. The books I've completed so far
are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;'The Worthing Saga' …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;This year so far has been tough.&lt;/p&gt;
&lt;p&gt;I thought I would have read around 10 books by now but I'm barely
half that mark. Most of the books are mostly fiction, but at least
I've got some variety this time. The books I've completed so far
are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;'The Worthing Saga' by Orson Scott Card: This is a really
interesting read, although I disagree with what I think is the
core message of this book. This is that someone has to suffer so
that they can enjoy life fully, otherwise their lives are empty.&lt;/li&gt;
&lt;li&gt;'Deep Work' by Cal Newport: This has to be the best book I've
read this year. It will be even better if I can manage to put
the advice in this book into practice. It explains the concept
of concentrating on one's work and the advantages it adds to
one's life. This concept comes with various examples of people
that have applied deep work in their practice to successful
extents.&lt;/li&gt;
&lt;li&gt;'The Princess Bride' by William Goldman: The feel-good-book of
the year. The story just flows and its told in a weird way where
the author occassionally adds commentary to provide context or
sometimes give spoilers in the book.&lt;/li&gt;
&lt;li&gt;'Lauren Ipsum' by Carlos Bueno: This book is aimed at kids but
is really awesome. Its various puns and analogies to computers
were really cool.&lt;/li&gt;
&lt;li&gt;'The Great Hunt (Wheel of Time Book 2)' by Robert Jordan: This
series does get really interesting in book 2. The first book was
a bit dull but this picks up the pace to tell a great tale of
the Dragon.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some books I've started reading but yet to complete are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;'Professor Frisby's Mostly Adequate Guide to Functional Programming'
by Brian Lonsdorf: This explains functional programming concepts
using javascript. This has to be the book that got me interested
in functional programming, especially when the author explained
currying and composing. That was literally mind-blowing.&lt;/li&gt;
&lt;li&gt;'LearnYouAHaskell' by Miran Lipovaka: Decided to learn a purely
functional language after getting through some chapters of
Mostly Adequate. I'm barely done with the third chapter and I'm
reall liking this way of thinking.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I haven't blogged as much as I thought I would this year.
Basically the idea was to blog on what I was doing so that it
acts a means of documentation for my future self. I find it easier
to read my own words especially when its from a concept I had
forgotten about. The good thing is I have a lot of new things I've
learned, so I really need to pull up my pants. Some topics I've
really got into include:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Robotics: I'm thinking of making a javascript tool that will do
the forward kinematics, inverse kinematics, robotic dynamics
(Euler-Lagrange and Newton-Euler) and motion planning. I think
doing this will cement the knowledge I've got a bit more.&lt;/li&gt;
&lt;li&gt;Functional programming: Not sure of what to do, but I think I'll
look for a pet project that I can implement using haskell.&lt;/li&gt;
&lt;li&gt;Model Predictive Control and Advanced Control: These are some
really dope units I'm doing in my Master's program. Its mostly
theoretical, but I have to find something practical to use these
in. I mean, just thinking about these concepts puts a smile to
my face.&lt;/li&gt;
&lt;li&gt;Hybrid Energy Systems: This is what I want to focus on for my
Masters' thesis though I'm still looking for a gap here.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the &lt;a class="reference external" href="http://comics.jnduli.co.ke"&gt;comic site&lt;/a&gt;, I just
realized my art isn't that good. I think this has to do with
self-bias, where immediately after drawing something, I looked at
it and saw that it was good. But months later (when the feeling of
achievement has waned), I look at them objectively and I'm shocked
that I found them good. I've been looking at various videos and
trying to practice. This is something I intend to become better
at.&lt;/p&gt;
&lt;p&gt;I'm also in my second semester for masters in Mechatronics
Engineering. The course work is pretty interesting but difficult.
The killer feature though is the research work, more specifically
the research proposal. This becomes more impossible with every
passing day especially finding a viable gap. I had some things I
really wanted to get into, so I started digging in and reading
papers. I ended up (still do) frustrated and angry at myself
because I mostly couldn't understand these papers. And when I
finally get a paper I somehow understand, I can't find any gap to
fill. This has been going on for the past three months and its
maddenning. I've thought that there must be a better way to do
this, but this is the process my institution takes. I get my own
gap, and write a proposal around it (with barely any feedback or
help). So right now I'm just shooting in the dark and hoping
something comes up.&lt;/p&gt;
&lt;p&gt;For personal projects, &lt;a class="reference external" href="mradi.jnduli.co.ke"&gt;Mradi&lt;/a&gt; is coming up
nicely. Development has slowed down though in recent months.
Hopefully I will manage to finish this product soon. I also started
working on some financial tool called Staafu. It should basically
help one plan for retirement by maximizing investments and
reducing risks.&lt;/p&gt;
</content><category term="Random"/><category term="random"/></entry><entry><title>Document Scaning in Arch Linux</title><link href="https://blog.jnduli.co.ke/document-scaning-in-archgit-branches-basics.html" rel="alternate"/><published>2018-07-08T15:00:00+03:00</published><updated>2018-07-08T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-07-08:/document-scaning-in-archgit-branches-basics.html</id><summary type="html">&lt;p&gt;Using a scanner in arch is pretty perplexing at first, especially
if you want to try it from the command line. Here are my steps to
end up with something that works.&lt;/p&gt;
&lt;p&gt;First install the sane package. Sane provides a command line tool
for using scanners.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;sane …&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Using a scanner in arch is pretty perplexing at first, especially
if you want to try it from the command line. Here are my steps to
end up with something that works.&lt;/p&gt;
&lt;p&gt;First install the sane package. Sane provides a command line tool
for using scanners.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;sane
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the scanner is a hp brand, setting up hp-lip also helps out.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;hplip
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This gives features that help setting up the printer or scanner
easily like hp-setup. Using it and the various prompts, one can
set up the printer and scanner easily.&lt;/p&gt;
&lt;p&gt;Assuming the device has already been set up, find a list of
devices using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;scanimage&lt;span class="w"&gt; &lt;/span&gt;-L
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;My output looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;v4l:/dev/video0&lt;span class="s1"&gt;&amp;#39; is a Noname USB2.0 HD UVC WebCam: USB2.0 HD virtual device&lt;/span&gt;
&lt;span class="s1"&gt;device `hpaio:/net/HP_LaserJet_Pro_MFP_M127fw?ip=192.168.1.27&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;Hewlett-Packard&lt;span class="w"&gt; &lt;/span&gt;HP_LaserJet_Pro_MFP_M127fw&lt;span class="w"&gt; &lt;/span&gt;all-in-one
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To determine options for my device I have to do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;scanimage&lt;span class="w"&gt; &lt;/span&gt;--device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;device name&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-A
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which in my case is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;scanimage&lt;span class="w"&gt; &lt;/span&gt;--device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hpaio:/net/HP_LaserJet_Pro_MFP_M127fw?ip=192.168.1.27&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-A
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This in my case outputs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;All&lt;span class="w"&gt; &lt;/span&gt;options&lt;span class="w"&gt; &lt;/span&gt;specific&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;hpaio:/net/HP_LaserJet_Pro_MFP_M127fw?ip&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;192&lt;/span&gt;.168.1.27&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;:
&lt;span class="w"&gt;  &lt;/span&gt;Scan&lt;span class="w"&gt; &lt;/span&gt;mode:
&lt;span class="w"&gt;    &lt;/span&gt;--mode&lt;span class="w"&gt; &lt;/span&gt;Lineart&lt;span class="p"&gt;|&lt;/span&gt;Gray&lt;span class="p"&gt;|&lt;/span&gt;Color&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;Lineart&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Selects&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;scan&lt;span class="w"&gt; &lt;/span&gt;mode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;e.g.,&lt;span class="w"&gt; &lt;/span&gt;lineart,&lt;span class="w"&gt; &lt;/span&gt;monochrome,&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;color&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;    &lt;/span&gt;--resolution&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;150&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;1200dpi&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Sets&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;resolution&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;scanned&lt;span class="w"&gt; &lt;/span&gt;image.
&lt;span class="w"&gt;    &lt;/span&gt;--source&lt;span class="w"&gt; &lt;/span&gt;Flatbed&lt;span class="p"&gt;|&lt;/span&gt;ADF&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;Flatbed&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Selects&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;scan&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;such&lt;span class="w"&gt; &lt;/span&gt;as&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;document-feeder&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;  &lt;/span&gt;Advanced:
&lt;span class="w"&gt;    &lt;/span&gt;--brightness&lt;span class="w"&gt; &lt;/span&gt;-1000..1000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Controls&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;brightness&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;acquired&lt;span class="w"&gt; &lt;/span&gt;image.
&lt;span class="w"&gt;    &lt;/span&gt;--contrast&lt;span class="w"&gt; &lt;/span&gt;-1000..1000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Controls&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;contrast&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;acquired&lt;span class="w"&gt; &lt;/span&gt;image.
&lt;span class="w"&gt;    &lt;/span&gt;--compression&lt;span class="w"&gt; &lt;/span&gt;None&lt;span class="p"&gt;|&lt;/span&gt;JPEG&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;JPEG&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Selects&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;scanner&lt;span class="w"&gt; &lt;/span&gt;compression&lt;span class="w"&gt; &lt;/span&gt;method&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;faster&lt;span class="w"&gt; &lt;/span&gt;scans,&lt;span class="w"&gt; &lt;/span&gt;possibly&lt;span class="w"&gt; &lt;/span&gt;at
&lt;span class="w"&gt;        &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;expense&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;image&lt;span class="w"&gt; &lt;/span&gt;quality.
&lt;span class="w"&gt;    &lt;/span&gt;--jpeg-quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;..100&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;inactive&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Sets&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;scanner&lt;span class="w"&gt; &lt;/span&gt;JPEG&lt;span class="w"&gt; &lt;/span&gt;compression&lt;span class="w"&gt; &lt;/span&gt;factor.&lt;span class="w"&gt; &lt;/span&gt;Larger&lt;span class="w"&gt; &lt;/span&gt;numbers&lt;span class="w"&gt; &lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;better
&lt;span class="w"&gt;        &lt;/span&gt;compression,&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;smaller&lt;span class="w"&gt; &lt;/span&gt;numbers&lt;span class="w"&gt; &lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;better&lt;span class="w"&gt; &lt;/span&gt;image&lt;span class="w"&gt; &lt;/span&gt;quality.
&lt;span class="w"&gt;  &lt;/span&gt;Geometry:
&lt;span class="w"&gt;    &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;..215.9mm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Top-left&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;position&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;scan&lt;span class="w"&gt; &lt;/span&gt;area.
&lt;span class="w"&gt;    &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;..296.926mm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Top-left&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;position&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;scan&lt;span class="w"&gt; &lt;/span&gt;area.
&lt;span class="w"&gt;    &lt;/span&gt;-x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;..215.9mm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;215&lt;/span&gt;.9&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Width&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;scan-area.
&lt;span class="w"&gt;    &lt;/span&gt;-y&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;..296.926mm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;296&lt;/span&gt;.926&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Height&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;scan-area.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And using this information I can scan the document. For example to
output to a tiff file, I'll do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;scanimage&lt;span class="w"&gt; &lt;/span&gt;--device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hpaio:/net/HP_LaserJet_Pro_MFP_M127fw?ip=192.168.1.27&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--format&lt;span class="o"&gt;=&lt;/span&gt;tiff&lt;span class="w"&gt; &lt;/span&gt;--mode&lt;span class="o"&gt;=&lt;/span&gt;color&lt;span class="w"&gt;  &lt;/span&gt;--resolution&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;.tiff
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This sets the mode to color and the resolution to 75. These
options are found from the previous output.&lt;/p&gt;
&lt;p&gt;To get the output into a pdf file, I use tiff2pdf. If I have
multiple files that I scanned, I add them into a single file using
tiffcp.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;tiffcp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.tiff&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.tiff&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.tiff&lt;span class="w"&gt; &lt;/span&gt;output.tiff
tiffpdf&lt;span class="w"&gt; &lt;/span&gt;-j&lt;span class="w"&gt; &lt;/span&gt;output.tiff&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;output.pdf
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A more advanced example is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;tiff2pdf&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;letter&lt;span class="w"&gt; &lt;/span&gt;-j&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;title.pdf&lt;span class="w"&gt; &lt;/span&gt;doc.tiff
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However using tiff2pdf occasionally fails because libtiff has set and
upper limit of memory to be used by libjpeg. So if I have really
large tiff files, I'll most likely get the following error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;JPEGLib:&lt;span class="w"&gt; &lt;/span&gt;Backing&lt;span class="w"&gt; &lt;/span&gt;store&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;supported.
tiff2pdf:&lt;span class="w"&gt; &lt;/span&gt;Error&lt;span class="w"&gt; &lt;/span&gt;writing&lt;span class="w"&gt; &lt;/span&gt;encoded&lt;span class="w"&gt; &lt;/span&gt;strip&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;PDF&lt;span class="w"&gt; &lt;/span&gt;sm.pdf.
tiff2pdf:&lt;span class="w"&gt; &lt;/span&gt;An&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;occurred&lt;span class="w"&gt; &lt;/span&gt;creating&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;PDF&lt;span class="w"&gt; &lt;/span&gt;file.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I could not find a fix for this. So I just made sure my tiff files
were less than 10MB. If a file became more than that size, I
reduced the resolution of scanning. Also while combining files
using tiffcp, if the eventual tiff file is too big, I convert the
individual tiff files into pdfs and combine the pdfs using the
following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pdfunite&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.pdf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.pdf&lt;span class="w"&gt; &lt;/span&gt;output.pdf
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that is how I scan document in my arch setup.&lt;/p&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>When Memory is not enough</title><link href="https://blog.jnduli.co.ke/when-memory-is-not-enough.html" rel="alternate"/><published>2018-05-31T16:00:00+03:00</published><updated>2018-05-31T16:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-05-31:/when-memory-is-not-enough.html</id><summary type="html">&lt;p&gt;A computer or server suddenly freezes or crashes. You don't know
what the problem is and you really need to complete this task. One
of the options is to consider memory. You might have just run out.
To confirm this, you can monitor memory usage using the htop
command while …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A computer or server suddenly freezes or crashes. You don't know
what the problem is and you really need to complete this task. One
of the options is to consider memory. You might have just run out.
To confirm this, you can monitor memory usage using the htop
command while the operation is running. This has occured to me
multiple times, most recently while installing tor using yaourt,
compiling a nodejs project and compiling hledger.&lt;/p&gt;
&lt;p&gt;To fix this, one needs to increase the size of swap. Swap is the
portion of the hard disk that the OS will use when memory runs
out, like some form of virtual memory. It is usually existent on
most linux installations (You probably set one yourself), but you
can increase this to cater for this unique situation.&lt;/p&gt;
&lt;p&gt;So to do this, first allocate some diskspace that will be used for
this task. This saves us this space and it cannot be used for any
other task. Afterwards change the ownership and permissions of the
allocated space, then set it up as a linux swap space and finally
enable it so that the OS can use it for swapping..&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;fallocate&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;10G&lt;span class="w"&gt; &lt;/span&gt;/swapfile
sudo&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/swapfile
sudo&lt;span class="w"&gt; &lt;/span&gt;mkswap&lt;span class="w"&gt; &lt;/span&gt;/swapfile
swapon&lt;span class="w"&gt; &lt;/span&gt;/swapfile
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, you can run whatever task was failing/crashing. After the
task successfully runs, you might want to disable this new space.
To do that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;swapoff&lt;span class="w"&gt; &lt;/span&gt;-a
rm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;/swapfile
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To improve performance, one can try to experiment with the virtual
memory subsystem. More on this can be found in the documentation
for &lt;a class="reference external" href="https://www.kernel.org/doc/Documentation/sysctl/vm.txt"&gt;vm&lt;/a&gt;. For
example, I tried this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sysctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;swappiness&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="nv"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sysctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;vfs_cache_pressure&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make the changes permanent, one can try this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;/etc/fstab&lt;span class="w"&gt; &lt;/span&gt;/etc/fstab.bak&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#create backup just in case something fails&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/swapfile none swap sw 0 0&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;/etc/fstab
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vm.swappiness=10&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;/etc/sysctl.conf
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vm.vfs_cache_pressure=50&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;/etc/sysctl.conf
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The source for these commands is from the &lt;a class="reference external" href="https://wiki.archlinux.org/index.php/Swap"&gt;archlinux_wiki&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"/><category term="linux"/><category term="server"/></entry><entry><title>Jogging Time Tracking In Google Sheets</title><link href="https://blog.jnduli.co.ke/jogging-time-tracking=in-google-sheets.html" rel="alternate"/><published>2018-03-31T19:00:00+03:00</published><updated>2018-03-31T19:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-03-31:/jogging-time-tracking=in-google-sheets.html</id><summary type="html">&lt;p&gt;I jog frequently. I needed to track the various times I spend
jogging my various routes. There are pretty awesome android apps
for this but carrying a phone with me while jogging did not work.
I was ok with a wrist watch though. So I jog and afterwards store
the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I jog frequently. I needed to track the various times I spend
jogging my various routes. There are pretty awesome android apps
for this but carrying a phone with me while jogging did not work.
I was ok with a wrist watch though. So I jog and afterwards store
the time and route taken in google sheets. A sample table would
look like this:&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;colgroup&gt;
&lt;col width="39%" /&gt;
&lt;col width="29%" /&gt;
&lt;col width="32%" /&gt;
&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;Route&lt;/td&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2018-01-04&lt;/td&gt;
&lt;td&gt;Route A&lt;/td&gt;
&lt;td&gt;21.40.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2018-01-05&lt;/td&gt;
&lt;td&gt;Route A&lt;/td&gt;
&lt;td&gt;21.78.80&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;It becomes hard to gain insight into this table if it becomes too
long. So I needed a method of getting basic metrics from this
data. This was the average times I spend on a route and the best
time recorded on a route.&lt;/p&gt;
&lt;p&gt;I could not find a function I could easily use to get this
information. This was because I store my times in a weird format,
that is Minutes.Seconds.Centiseconds. I used this because it is
what my wrist watch gave me. So I had to write my own custom
functions.&lt;/p&gt;
&lt;p&gt;Before doing calculations in time, it is best to convert it all to
the smallest unit you have (in my case it was centiseconds). This
is the function I came up with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getTimeInMicroSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeGiven&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeGiven&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mf"&gt;6000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mf"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So to get the average of a group of times, you just add up the
times in milliseconds, then find the average in milliseconds, and
convert the average back to minutes, seconds and hours. To do
that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;  var total_time = 0;
  var total = input.length;

  for (var i =0 ; i&amp;lt;total; i++){
    var time = getTimeInMicroSeconds(input[i]);
    total_time += time;
  }

  var average_time = Math.floor(total_time/total);
  var microseconds = average_time % 100;
  var seconds = Math.floor(average_time/100) % 60;
  var minutes = Math.floor(average_time/60000);
  return correctSizeString(minutes,2)+&amp;quot;.&amp;quot;+correctSizeString(seconds,2)+&amp;quot;.&amp;quot;+correctSizeString(microseconds,2);
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The function correctSizeString just ensures the times are
appropriately sized e.g. instead of showing 6 in seconds time, it
will show 06.&lt;/p&gt;
&lt;p&gt;To find the best time, I came up with this function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BESTTIME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;minimum_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;index_minimum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getTimeInMicroSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;minimum_time&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;minimum_time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;index_minimum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index_minimum&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And this is one of the functions I use to get average time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;AVERAGETIME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FILTER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$C$2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;$C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;$B$2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;$B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;$E2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The function filters the input based on what is in row B (which is
the route) and finds the average of the times of a particular
route.&lt;/p&gt;
&lt;p&gt;The complete script can be viewed from this &lt;a class="reference external" href="https://gist.github.com/jnduli/9805e638c5da083070df033592fb1b13"&gt;gist&lt;/a&gt;.&lt;/p&gt;
</content><category term="Computer"/><category term="projects"/></entry><entry><title>Testing Asynchronous Calls in VueJS</title><link href="https://blog.jnduli.co.ke/testing-asynchronous-calls-in-vue.html" rel="alternate"/><published>2018-03-16T15:00:00+03:00</published><updated>2018-03-16T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-03-16:/testing-asynchronous-calls-in-vue.html</id><summary type="html">&lt;p&gt;I frequently use asynchronous calls when coding in vuejs,
especially when I get and send data to an online api. Initially, I
found it difficult to test the asynchronous calls, but as I
learned more, asynchronous tests became painless. I detail the
methods I use to test promises and async …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I frequently use asynchronous calls when coding in vuejs,
especially when I get and send data to an online api. Initially, I
found it difficult to test the asynchronous calls, but as I
learned more, asynchronous tests became painless. I detail the
methods I use to test promises and async calls in this article.
The snippets here assume you are using axios for http requests and
the vuejs project uses vuex for state management.&lt;/p&gt;
&lt;p&gt;This is a simple vuex store that can get a random quote or a list
of quotes from &lt;a class="reference external" href="http://quotesondesign.com/"&gt;this online api&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vuex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vuex&amp;#39;&lt;/span&gt;

&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Vuex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vuex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;mutations&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;setQuotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newQuotes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newQuotes&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;setRandomQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;getQuotes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://quotesondesign.com/wp-json/posts&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;setQuotes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;getRandomQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&amp;amp;filter[posts_per_page]=1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;setRandomQuote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is vue component that will display the list of random quotes got:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Random&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Quote&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;random-quote&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;item in randomQuote&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;item.ID&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/div&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;randomQuote === null&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/div&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;get-random&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;getQuote&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;GetRandomQuote&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/button&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/div&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/template&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mapState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vuex&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;GetQuotes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;getQuote&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;getRandomQuote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/script&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If I want to test the getQuote method, I'll have to figure out how
to make the asyc ajax call to the server. Since the call happens
in another thread, it becomes tricky, because I have to wait for
that thread to finish before testing the result. Luckily, there is
a library called &lt;a class="reference external" href="https://github.com/axios/moxios"&gt;moxios&lt;/a&gt;. To
set it up on the project, do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;npm&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;moxios&lt;span class="w"&gt; &lt;/span&gt;--save-dev
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With moxios, I can mock the ajax calls (from axios). With this, I
get dummy content that the test can treat similarly to how the
component will treat server results. Moxios also has a wait function, which will pause execution of test until the promise completes. To test the above component with moxios:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vuex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vuex&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vue-test-utils&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;RandomQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@/components/RandomQuote&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;@/store&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;axios&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;VueAxios&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vue-axios&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;moxios&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;moxios&amp;#39;&lt;/span&gt;

&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Vuex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;VueAxios&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Login.vue&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;moxios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;moxios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stubRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&amp;amp;filter[posts_per_page]=1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1622&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Stephen Anderson&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;p&amp;gt;At this point in experience design evolution, satisfaction ought to be the norm, and delight out to be the goal.&amp;lt;/p&amp;gt;\n&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RandomQuote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;moxios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uninstall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;should show random quote when clicked&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#get-random&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;moxios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#random-quote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;At this point in experience design evolution, satisfaction ought to be the norm, and delight out to be the goal.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From the above, I use stubRequest to mock the http request. In the
actual test, I use moxios.wait(), which will wait until the api
call completes before testing the contents of the random quote. I
like this method because it means I get to test the store
indirectly while testing my components.&lt;/p&gt;
&lt;p&gt;Instead of moxios.call(), I could use vue's nextTick(), which
also waits for the promise to complete.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;should show random quote when clicked&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#get-random&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$nextTick&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#random-quote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;At this point in experience design evolution, satisfaction ought to be the norm, and delight out to be the goal.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another cleaner method of testing promises is using the library
&lt;a class="reference external" href="https://github.com/kentor/flush-promises"&gt;flush-promises&lt;/a&gt;. With
flush-promises, the test would look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;should show random quote when clicked&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#get-random&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;flushPromises&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#random-quote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;At this point in experience design evolution, satisfaction ought to be the norm, and delight out to be the goal.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The advantage flushPromises has is that if the component has
multiple asynchronous calls at the same time e.g. call to user api
to confirm if logged in, get list of quotes, get comments, and
for some reason the test does not work, we can just add multiple
flushPromises in the test.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;should show random quote when clicked&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#get-random&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;flushPromises&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;flushPromises&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#random-quote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;At this point in experience design evolution, satisfaction ought to be the norm, and delight out to be the goal.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"/><category term="projects"/><category term="programming"/></entry><entry><title>Jupyter Notebook Setup on a VPS</title><link href="https://blog.jnduli.co.ke/jupyter-notebook-setup-in-vps.html" rel="alternate"/><published>2018-03-02T15:00:00+03:00</published><updated>2018-03-02T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-03-02:/jupyter-notebook-setup-in-vps.html</id><summary type="html">&lt;p&gt;These steps have been tested on Digital Ocean server and a
scaleway ARM64 server. I used the cheapest provided options for my
setups.&lt;/p&gt;
&lt;p&gt;First, set up ubuntu on the server. Both Digital Ocean and
Scaleway provide an easy way to do this. Just follow their
prompts, and you'll have your …&lt;/p&gt;</summary><content type="html">&lt;p&gt;These steps have been tested on Digital Ocean server and a
scaleway ARM64 server. I used the cheapest provided options for my
setups.&lt;/p&gt;
&lt;p&gt;First, set up ubuntu on the server. Both Digital Ocean and
Scaleway provide an easy way to do this. Just follow their
prompts, and you'll have your server up and running. After the
server is ready, update ubuntu:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;update
sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;upgrade
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The server only has the root user. It is not advisable to use root
for normal work. So, I create a new user and switch to it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;useradd&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/bin/bash&lt;span class="w"&gt; &lt;/span&gt;user
usermod&lt;span class="w"&gt; &lt;/span&gt;-aG&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;username
sudo&lt;span class="w"&gt; &lt;/span&gt;passwd&lt;span class="w"&gt; &lt;/span&gt;username
su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;user
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pip will be used to install various python packages. To install
it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;python3-pip
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then install various ml libraries I'll use later:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;python3&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;--user&lt;span class="w"&gt; &lt;/span&gt;numpy&lt;span class="w"&gt; &lt;/span&gt;scipy&lt;span class="w"&gt; &lt;/span&gt;matplotlib&lt;span class="w"&gt; &lt;/span&gt;pandas&lt;span class="w"&gt; &lt;/span&gt;sympy&lt;span class="w"&gt; &lt;/span&gt;nose&lt;span class="w"&gt; &lt;/span&gt;seaborn&lt;span class="w"&gt; &lt;/span&gt;pillow&lt;span class="w"&gt; &lt;/span&gt;keras&lt;span class="w"&gt; &lt;/span&gt;tensorflow&lt;span class="w"&gt; &lt;/span&gt;scikit-learn&lt;span class="w"&gt; &lt;/span&gt;scikit-image&lt;span class="w"&gt; &lt;/span&gt;kaggle-cli
pythom3&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;ipython&lt;span class="o"&gt;[&lt;/span&gt;notebook&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jupyter
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When setting up scaleway, some of the libraries failed to
install. Here are the dependenices I had to install for pillow:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;libtiff5-dev&lt;span class="w"&gt; &lt;/span&gt;libjpeg8-dev&lt;span class="w"&gt; &lt;/span&gt;zlib1g-dev&lt;span class="w"&gt; &lt;/span&gt;libfreetype6-dev&lt;span class="w"&gt; &lt;/span&gt;liblcms2-dev&lt;span class="w"&gt; &lt;/span&gt;libwebp-dev&lt;span class="w"&gt; &lt;/span&gt;tcl8.6-dev&lt;span class="w"&gt; &lt;/span&gt;tk8.6-dev&lt;span class="w"&gt; &lt;/span&gt;python-tk
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And here are the dependencies I had to install for scikit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;gfortran&lt;span class="w"&gt; &lt;/span&gt;python-dev&lt;span class="w"&gt; &lt;/span&gt;libopenblas-dev&lt;span class="w"&gt; &lt;/span&gt;liblapack-dev
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And for kaggle-cli too, I had to do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;libxml2-dev&lt;span class="w"&gt; &lt;/span&gt;libxslt1-dev&lt;span class="w"&gt; &lt;/span&gt;python3-lxml
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Tensorflow cannot be installed in the arm64 scaleway instance
using pip. So remove it from the packages.&lt;/p&gt;
&lt;p&gt;The packages are installed, but cannot be got from the terminal.
This is because the bash environment does not have it in its PATH
variable. To fix this, add this to the ~/.profile file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.local/bin&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.local/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Having set up most of the libraries I'll need, I have to configure
jupyter so that I can access it from my browser.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;jupyter&lt;span class="w"&gt; &lt;/span&gt;notebook&lt;span class="w"&gt; &lt;/span&gt;--generate-config
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A file is generated in ~/.jupyter/jupyter_notebook_config.py. This
file contains various configuration options for jupyter.&lt;/p&gt;
&lt;p&gt;I change the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotebookApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open_browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotebookApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;0.0.0.0&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To set up the password to be used on logging in do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;jupyter&lt;span class="w"&gt; &lt;/span&gt;notebook&lt;span class="w"&gt; &lt;/span&gt;password
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then start jupyter using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nohup&lt;span class="w"&gt; &lt;/span&gt;jupyter&lt;span class="w"&gt; &lt;/span&gt;notebook
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The jupyter can be accessed from : ip_address:8888 using any browser.&lt;/p&gt;
&lt;p&gt;To install Tensorflow on scaleway's arm processors, I found
instructions for a custom build &lt;a class="reference external" href="https://github.com/lherman-cs/tensorflow-aarch64"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The instructions are to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-L&lt;span class="w"&gt; &lt;/span&gt;https://github.com/lherman-cs/tensorflow-aarch64/releases/download/r1.4/tensorflow-1.4.0rc0-cp35-cp35m-linux_aarch64.whl&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/tmp/tensorflow-1.4.0rc0-cp35-cp35m-linux_aarch64.whl
python3&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;/tmp/tensorflow-1.4.0rc0-cp35-cp35m-linux_aarch64.whl
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"/><category term="projects"/></entry><entry><title>Control: Controllability and Observability</title><link href="https://blog.jnduli.co.ke/control-controllability-and-observability.html" rel="alternate"/><published>2018-02-21T15:00:00+03:00</published><updated>2018-02-21T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-02-21:/control-controllability-and-observability.html</id><summary type="html">&lt;p&gt;The state space equations are given by:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{align*}
x'(t) = Ax(t) + Bu(t)\\
y(t) = Cx(t) + Du(t)
\end{align*}
&lt;/div&gt;
&lt;p&gt;If we discretize the system, the equation can be written as:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{align*}
x(n+1) = A_dx(n) + B_du(n)\\
y(n) = C_dx(n) + D_du(n)
\end …&lt;/div&gt;</summary><content type="html">&lt;p&gt;The state space equations are given by:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{align*}
x'(t) = Ax(t) + Bu(t)\\
y(t) = Cx(t) + Du(t)
\end{align*}
&lt;/div&gt;
&lt;p&gt;If we discretize the system, the equation can be written as:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{align*}
x(n+1) = A_dx(n) + B_du(n)\\
y(n) = C_dx(n) + D_du(n)
\end{align*}
&lt;/div&gt;
&lt;p&gt;The discretization steps can be found &lt;a class="reference external" href="https://en.wikibooks.org/wiki/Control_Systems/State-Space_Equations#Discretization"&gt;here:discretization&lt;/a&gt;&lt;/p&gt;
&lt;div class="section" id="controllability"&gt;
&lt;h2&gt;Controllability&lt;/h2&gt;
&lt;p&gt;A system is said to be controllable if the state can be changed by
changing the inputs.&lt;/p&gt;
&lt;p&gt;Using the discretized equation, we can come up with the following:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{align*}
x(1) &amp;amp;= A_dx(0) + B_du(0)\\
x(2) &amp;amp;= A_dx(1) + B_du(1) = A_d^2 x(0) + A_dB_du(0) + B_du(1)\\
.\\
x(n) &amp;amp;= A_d^n x(0) + A_d^{n-1}B_du(0) + A_d^{n-2}B_du(1) + ...
+ B_du(n-1)
\end{align*}
&lt;/div&gt;
&lt;p&gt;The last equation can be written as:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{equation*}
x(n) -  A_d^n x(0)=
\begin{bmatrix}
B_d &amp;amp; A_dB_d &amp;amp; A_d^2B_d &amp;amp; ... &amp;amp; A_d^{n-2}B_d &amp;amp; A_d^{n-1}B_d
\end{bmatrix} *
\begin{bmatrix}
u(n-1) \\ . \\ . \\ . \\u(2) \\ u(1) \\ u(0)
\end{bmatrix}
\end{equation*}
&lt;/div&gt;
&lt;p&gt;Replacing with the controllability matrix with C, we get:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{align*}
x(n) - A_d^n x(0) = C * U \\
\therefore\\
U = C^{-1} * (x(n) - A_d^n x(0))
\end{align*}
&lt;/div&gt;
&lt;p&gt;This means that the equation is solvable when &lt;span class="math"&gt;\(C^{-1}\)&lt;/span&gt; exists,
i.e. its a non singular matrix.&lt;/p&gt;
&lt;p&gt;Therefore a system is controllable when:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{equation*}
\begin{bmatrix}
B_d &amp;amp; A_dB_d &amp;amp; A_d^2B_d &amp;amp; ... &amp;amp; A_d^{n-2}B_d &amp;amp; A_d^{n-1}B_d
\end{bmatrix}
\end{equation*}
&lt;/div&gt;
&lt;p&gt;has a determinant.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="observability"&gt;
&lt;h2&gt;Observability&lt;/h2&gt;
&lt;p&gt;Using the discretized equation too:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{align*}
y(0) = C_dx(0)\\
y(1) = C_dx(1) = C_dA_dx(0)\\
y(2) = C_dx(2) = C_dA_d^2x(0) \\
y(n) = C_dx(n) = C_dA_d^nx(0)
\end{align*}
&lt;/div&gt;
&lt;p&gt;This can be written as:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{equation*}
\begin{bmatrix}
y(0)\\y(1)\\y(2)\\.\\y(n)
\end{bmatrix} =
\begin{bmatrix}
C_d \\ C_dA_d \\ C_dA_d^2 \\ . \\C_dA_d^n
\end{bmatrix} *
x(0)
\end{equation*}
&lt;/div&gt;
&lt;p&gt;The observability matrix is:&lt;/p&gt;
&lt;div class="math"&gt;
\begin{equation*}
\begin{bmatrix}
C_d \\ C_dA_d \\ C_dA_d^2 \\ . \\C_dA_d^n
\end{bmatrix}
\end{equation*}
&lt;/div&gt;
&lt;p&gt;And the systems has a unique solution if the system has a rank n.
If the system is a square matrix, the solution is of rank n if the
determinant is not 0.&lt;/p&gt;
&lt;p&gt;The observability and controllability derivations can be found
from &lt;a class="reference external" href="http://www.ece.rutgers.edu/~gajic/psfiles/chap5.pdf"&gt;here:rutgers&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;script type='text/javascript'&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Engineering"/><category term="control"/></entry><entry><title>SSH AND SERVERS</title><link href="https://blog.jnduli.co.ke/ssh-and-servers.html" rel="alternate"/><published>2018-02-16T15:00:00+03:00</published><updated>2018-02-16T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-02-16:/ssh-and-servers.html</id><summary type="html">&lt;p&gt;SSH provides a secure means of remote login from one computer to
another computer. When setting up linux servers, the OS usually
provides ssh by default. To login:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;user@ipaddress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This prompts for a password, after which you have access to a
remote terminal. Sometimes, no password is requested …&lt;/p&gt;</summary><content type="html">&lt;p&gt;SSH provides a secure means of remote login from one computer to
another computer. When setting up linux servers, the OS usually
provides ssh by default. To login:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;user@ipaddress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This prompts for a password, after which you have access to a
remote terminal. Sometimes, no password is requested, and you are
required to set one up after your first login.&lt;/p&gt;
&lt;p&gt;The password login method is not really secure. This is because
someone can try to guess it. A more secure method is to disable
the password login and set up ssh-keys on the server. Therefore,
someone will need to have the private ssh-key to be able to access
your server.&lt;/p&gt;
&lt;p&gt;To generate a key:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ssh-keygen&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;rsa&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;comment&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There will be some prompts that guide you through the process. If
you choose to save the key in the default location, this key will
be used wheneve a custom key is not provided. You should take care
however, since you can easily overwrite a key that was in use.
The command generates two files, the private key and a public key
( has a .pub suffix).&lt;/p&gt;
&lt;p&gt;To set up the key, copy the public key to the server by:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;file.pub&lt;span class="w"&gt; &lt;/span&gt;user@ipaddress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you are copying the keys found in the default location i.e.
~/.ssh/id_rsa.pub, the -i option can be ignored.&lt;/p&gt;
&lt;p&gt;Having set the key up on the server, you can log in using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;/path/to/privatekey&lt;span class="w"&gt; &lt;/span&gt;user@ipaddress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If using the default file location, the -i option can be ignored.&lt;/p&gt;
&lt;p&gt;To disable the password login option, log into the server and
edit the /etc/ssh/sshd_config file (to disable password access for
the server) or ~/.ssh/config file (to disable password access for
a specific user). The following line should be added to the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;PasswordAuthentication&lt;span class="w"&gt; &lt;/span&gt;no
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After this, restart ssh using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;reload&lt;span class="w"&gt; &lt;/span&gt;ssh
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="section" id="ssh-forwarding"&gt;
&lt;h2&gt;SSH Forwarding&lt;/h2&gt;
&lt;p&gt;SSH forwarding is where the private key used to login to the
server, can be used by the server to perform some tasks. This is
useful in CI/CD, or when working with git on a server(Need to
push to a repository on github).&lt;/p&gt;
&lt;p&gt;To enable this, edit the ~/.ssh/config file from the local
machine and add:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Host&lt;span class="w"&gt; &lt;/span&gt;example.com
&lt;span class="w"&gt;    &lt;/span&gt;ForwardAgent&lt;span class="w"&gt; &lt;/span&gt;yes
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To set up the key for use by the server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;ssh-agent&lt;span class="k"&gt;)&lt;/span&gt;
ssh-add&lt;span class="w"&gt; &lt;/span&gt;~/.ssh/key
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Eval sets environment variables to ouput of ssh-agent. To confirm
the key has been added, you can do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ssh-add&lt;span class="w"&gt; &lt;/span&gt;-L
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you connect to the server example.com, it will now have you
private sshkey in its environment and can be used to access
repositories, other servers, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="frozen-ssh-session"&gt;
&lt;h2&gt;Frozen ssh session&lt;/h2&gt;
&lt;p&gt;Sometimes after connecting to the server, you might lose your
internet connection or hibernate/sleep you computer. The ssh
prompt after this will be frozen, with no commands running. To fix
this, you have to leave the prompt and log in again to the server.
To do this, press the following keys in order from the prompt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Enter
~
.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="linux"/><category term="server"/></entry><entry><title>System Clock Prescalers and Their Hazards</title><link href="https://blog.jnduli.co.ke/system_clock_prescalers_and_their_hazards.html" rel="alternate"/><published>2018-02-04T15:00:00+03:00</published><updated>2018-02-04T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-02-04:/system_clock_prescalers_and_their_hazards.html</id><summary type="html">&lt;p&gt;One means of saving power with the attiny13A is by slowing down
the clock frequency of the microcontroller. One option of doing
this is by using the system clock prescaler. The attiny13A is
shipped with running on a 9.6MHz internal RC Oscillator. It has
the CKDIV8 fuse set (which …&lt;/p&gt;</summary><content type="html">&lt;p&gt;One means of saving power with the attiny13A is by slowing down
the clock frequency of the microcontroller. One option of doing
this is by using the system clock prescaler. The attiny13A is
shipped with running on a 9.6MHz internal RC Oscillator. It has
the CKDIV8 fuse set (which provides a system clock prescaler of
8), thus it runs on a frequency of 1.2MHz.&lt;/p&gt;
&lt;p&gt;Supposing we want to slow it further, we can set up the CLKPR
(Clock Prescale Register) bits for the same. If we set this to a
prescaler of 16 for example, the attiny will run at a frequency of
600KHz. However, there is a special write procedure provided for
this to prevent unintentional changes:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Write the Clock Prescaler Change Enable (CLKPCE) bit to one and all other bits in
CLKPR to zero.&lt;/li&gt;
&lt;li&gt;Within four cycles, write the desired value to CLKPS while writing a zero to CLKPCE.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To follow this, our code will be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// set CLKPCE to 1 and other bits to zero&lt;/span&gt;
&lt;span class="n"&gt;CLKPR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mb"&gt;0b10000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// set prescaler to 256&lt;/span&gt;
&lt;span class="n"&gt;CLKPR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mb"&gt;0b00001000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Furthermore, when compiling we have to use the optimization flags
-0s, otherwise the process might take more than four cycles. The
microcontroller will be running at a clock speed of 37.5KHz after
the operation.&lt;/p&gt;
&lt;div class="section" id="hazards"&gt;
&lt;h2&gt;Hazards&lt;/h2&gt;
&lt;p&gt;If successful, however, programming the microcontroller will be
difficult. This is because of syncing issues, whereby the
microcontroller is significantly slower than the programmer. To
fix this you can set the -B flag using avrdude. However, the
usbasp programmer I am using does not have this functionality.&lt;/p&gt;
&lt;p&gt;To fix this we have to analyze how the microcontroller sets the
new frequency. First, the microcontroller will boot up. At this
state CLKPR is still its default value. Then the two instructions
setting the prescaler are run. This therefore means that if we can
find a way to stop those two instructions from running, we can
program the microcontroller with another firmware.&lt;/p&gt;
&lt;p&gt;IF we activate the RESET pin, before the clock prescaler is set,
the chip can be reprogrammed. Connect Ground signal to the RESET
pin and then provide power to the programmer (usbasp). This
maintains the microcontroller in Reset mode, thus the instructions
changing the prescaler are not carried out. Then immediately flash
the attiny. If successful, the error will be gone.&lt;/p&gt;
&lt;p&gt;Another way to prevent this is to have a considerable delay before
the CLKPCE bits are set. This delay allows for reprogramming if
necessary.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Engineering"/><category term="projects"/></entry><entry><title>SciKit-Learn GraphSearch CV</title><link href="https://blog.jnduli.co.ke/scikit-learn-graphsearch-cv.html" rel="alternate"/><published>2018-01-24T19:00:00+03:00</published><updated>2018-01-24T19:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-01-24:/scikit-learn-graphsearch-cv.html</id><summary type="html">&lt;p&gt;Scikit learn provides a lot of algorithms to help in machine
learning. However, sometimes those algorithms have too many
options. It is not usually evident which options will produce the
best results. One method of solving this is to loop through all
possible options and check the score.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;crit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gini …&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Scikit learn provides a lot of algorithms to help in machine
learning. However, sometimes those algorithms have too many
options. It is not usually evident which options will produce the
best results. One method of solving this is to loop through all
possible options and check the score.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;crit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gini&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;entropy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;max_depth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;min_samples_split&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;best_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;best_tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;criterion&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;crit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;max_depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;min_samples&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;min_samples_split&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;tr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;criterion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;criterion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;min_samples_split&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;min_samples&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;cur_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;best_score&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;best_core&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cur_score&lt;/span&gt;
                &lt;span class="n"&gt;best_tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is rather tedious and with more options to consider, the code
can become unreadable. Luckily, scikit-learn provides a method of
automatically doing this. All you do is provide a matrix of
options and scikit learn will loop through all possible
combinations to get the best fit for your data. It even provides
the options that worked best.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sklearn.model_selection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cross_val_score&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sklearn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sklearn.model_selection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GridSearchCV&lt;/span&gt;

&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;criterion&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gini&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;entropy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="s1"&gt;&amp;#39;min_samples_split&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="s1"&gt;&amp;#39;max_depth&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="s1"&gt;&amp;#39;class_weight&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;balanced&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="s1"&gt;&amp;#39;presort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
             &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;tr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecisionTreeClassifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;gsearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GridSearchCV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;gsearch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gsearch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;best_estimator_&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"/><category term="machine-learning"/></entry><entry><title>Ansible</title><link href="https://blog.jnduli.co.ke/ansible.html" rel="alternate"/><published>2018-01-06T18:00:00+03:00</published><updated>2018-01-06T18:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-01-06:/ansible.html</id><summary type="html">&lt;p&gt;Ansible is an automation tool that easens work a lot. I just set
it up once and from then on I can forget about configurations and
settings for my projects. It's really great for doing repeatable
tasks like setting up nginx for subdomains, redeploying django
projects, updating the OS, etc …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ansible is an automation tool that easens work a lot. I just set
it up once and from then on I can forget about configurations and
settings for my projects. It's really great for doing repeatable
tasks like setting up nginx for subdomains, redeploying django
projects, updating the OS, etc.&lt;/p&gt;
&lt;p&gt;For example, to set up a script that updates the server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;---

- hosts: my_server
   vars_files:
     - vars.yml
   remote_user: &amp;quot;{{ user }}&amp;quot;
   become: true
   tasks:
       - name: Running update and safe-upgrade
          apt:
              update_cache=yes
              upgrade=dist
          register: result
       - debug: var=result.stdout_lines
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I store my variables in the vars.yml file. In the example above,
the user variable is found here. The file looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;---

user: thisuser
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The my_server variable is set in /etc/ansible/hosts file and looks
like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;[my_server]&lt;/span&gt;
&lt;span class="na"&gt;random_url.co.ke&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since updating the system requires admin priviledges, make sure
the user has those permissions. This is why the script has
remote_user and become in its body. Also ansible will need to run
with these priviledges, so to do so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;--ask-become-pass&lt;span class="w"&gt; &lt;/span&gt;updates.yml
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And just like that the system gets updated. This asks for the
server password for the elevated user.&lt;/p&gt;
&lt;p&gt;Let's say I want to update my nginx config files to enable another
subdomain. Ansible should upload my config file to my server and
also restart nginx so that these changes are accepted.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;---
- hosts: my_server
   vars_files:
     - vars.yml

   tasks:
   # copy project nginx set up to server
     - name: set up nginx config on server
        remote_user: &amp;quot;{{ user }}&amp;quot;
        become: true
        template:
          src=config/nginx.j2
          dest=/etc/nginx/sites-enabled/{{ project_name }}
        notify:
          - restart nginx

   handlers:
     - name: restart nginx
        remote_user: &amp;quot;{{ user }}&amp;quot;
        become: true
        service: name=nginx state=restarted
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since ansible supports jinja templating, the nginx config file is
written in this format. Also the variables project_name and user
are found from the vars.yml file. What the above does is copy the
nginx config file to /etc/nginx/sites-enabled/project_name
restarts nginx.&lt;/p&gt;
&lt;p&gt;Here is the template used. You can also use variables defined in
the vars.yml in the template too, which is really helpful.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;server {
#listen 443;
    listen 80;
    server_name {{ server_name }};
    charset utf-8;
    client_max_body_size 2M;

    location / {
        # django
        include proxy_params;
        proxy_pass http://unix:{{ sock_file }};
    }

    location /static {
        autoindex on;
        alias {{ static_root }};
    }

    location /media {
        autoindex on;
        alias {{ media_root }};
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some commands can run with ansible-playbook file.yml but others
need elevated permissions. To help me deal with this I usually
have a Makefile in my ansible playbooks directory. For example to
deal with the two configs above, I'd have:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;ANSIBLE_SUDO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;--ask-become-pass

&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;ANSIBLE_SUDO&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;updates.yml

&lt;span class="nf"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="c"&gt;    #(ANSIBLE_SUDO) nginx_setup.yml&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can find moer about ansible &lt;a class="reference external" href="https://www.ansible.com/"&gt;here&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"/><category term="programming"/><category term="server"/></entry><entry><title>Summary of 2017</title><link href="https://blog.jnduli.co.ke/summary-of-2017.html" rel="alternate"/><published>2018-01-01T15:00:00+03:00</published><updated>2018-01-01T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2018-01-01:/summary-of-2017.html</id><summary type="html">&lt;p&gt;2017 was an interesting year in my life. I achieved a lot during
this time despite starting off on a low note. It started off on a
low note because following my graduation(2016), I was abit
confused with my life. Things however became better as the year
progressed.&lt;/p&gt;
&lt;p&gt;I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;2017 was an interesting year in my life. I achieved a lot during
this time despite starting off on a low note. It started off on a
low note because following my graduation(2016), I was abit
confused with my life. Things however became better as the year
progressed.&lt;/p&gt;
&lt;p&gt;I got my first job as a systems engineer at Koko Networks. I
learnt a lot while I was there: circuit design, firmware
development, managing and motivating teams and engineering
operations in general. The team at Koko was really helpful and
great. For that, I am grateful.&lt;/p&gt;
&lt;p&gt;I also made my first production circuits this year. The first was
a simple LED multiplexing array that was used to display various
texts. The second was a simple auto-agriculture kit for Aura
Engineering. These projects made me learn a lot about Kicad and
how to deal with PCB manufacturers.&lt;/p&gt;
&lt;p&gt;I was also an active contributor in the GrabCad community. I
uploaded a total of 20 models in 2017. I have learnt a lot about
using Solidworks and Inventor for design. I've experimented on
using FreeCAD in doing some design work and I'm impressed by the
many features it has. I want to do a lot more using FreeCAD
because I'm a huge open source enthusiast.&lt;/p&gt;
&lt;p&gt;In development, my first ever &amp;quot;serious&amp;quot; open source contribution
was accepted and merged to the main source tree. It was to add
support for rstcheck to vim-ale. Vim-ale is a vimscript linting
engine. I also made a comic site system in django that currently
runs on my server at &lt;a class="reference external" href="https://comics.jnduli.co.ke/"&gt;comics.jnduli.co.ke&lt;/a&gt;. For big projects, I started on
Mradi (an organisation system) which is still incomplete. Mradi's
tech stack uses: VueJS, ansible, django in the process.&lt;/p&gt;
&lt;p&gt;As far as infrastracture is concerned, I got to learn and use
ansible. Writing playbooks is fun, and automating steps is an
interesting challenge. Most of my projects currently have an
ansible config that helps in set up and configuration of various
tasks.&lt;/p&gt;
&lt;p&gt;Reading this year has been fruitful. The highlight of my year in
reading was completing the Foundation Trilogy by Isaac Asimov. It
taught me a lot about politics, economics and society. I also have
a huge catalog of unfinished books: Learn Vimscript the Hard Way,
The Art of Unix Programming and Thinking in Systems. These are
really great books that I should have completed.&lt;/p&gt;
&lt;p&gt;My participation in Urban Perspective (a bookclub) and Nailug
(Linux User Group) was also encouraging. I got to know so many
interesting people, learn from them, critique some ideas and
socialize.&lt;/p&gt;
&lt;p&gt;Finally, I got the PAUSTI scholarship. This was a pretty trying
moment for me because it meant I had to stop working and leave my
colleagues at Koko. This was a tough decision to make and leaving
Koko was a low point for me in 2017.&lt;/p&gt;
&lt;p&gt;2017 was a great year. That was my summary of the year, and now I
can see through 2018.&lt;/p&gt;
</content><category term="Random"/></entry><entry><title>Zealot B570 Bluetooth Headset</title><link href="https://blog.jnduli.co.ke/b570-zealot-headset-review.html" rel="alternate"/><published>2017-12-22T15:00:00+03:00</published><updated>2017-12-22T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-12-22:/b570-zealot-headset-review.html</id><summary type="html">&lt;p&gt;I got the zealot b570 a couple of months ago. I have been using it
since then and it has not disappointed. In fact, I really like
this headset. I'm also a bit clumsy, so it's been subjected to a
rough time, and its still working well.&lt;/p&gt;
&lt;div class="section" id="pros"&gt;
&lt;h2&gt;Pros&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Bluetooth capable …&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I got the zealot b570 a couple of months ago. I have been using it
since then and it has not disappointed. In fact, I really like
this headset. I'm also a bit clumsy, so it's been subjected to a
rough time, and its still working well.&lt;/p&gt;
&lt;div class="section" id="pros"&gt;
&lt;h2&gt;Pros&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Bluetooth capable&lt;/li&gt;
&lt;li&gt;SD card slot&lt;/li&gt;
&lt;li&gt;OK battery life&lt;/li&gt;
&lt;li&gt;I can listen to audio over mini usb and over 3.5 mm jack. I
prefer using the mini usb option, so that's a plus.&lt;/li&gt;
&lt;li&gt;Good audio quality&lt;/li&gt;
&lt;li&gt;Really durable. I've never had a head set that lasted more than
3 months. But this was primarily due to the 3.5 mm jack getting
cut / broken.&lt;/li&gt;
&lt;li&gt;The control buttons are located at a good location.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="cons"&gt;
&lt;h2&gt;Cons&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The headset was really tight and painful to wear. To fix it, I
stretched it for some days and it worked well.&lt;/li&gt;
&lt;li&gt;The LED lights are really annoying. I wish there were an option
to disable these.&lt;/li&gt;
&lt;li&gt;I don't use the FM mode, so it kind of disappoints me when I'm
switching modes and the noise from the FM mode comes up.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Random"/><category term="product"/><category term="review"/></entry><entry><title>Project Management in Google Sheets</title><link href="https://blog.jnduli.co.ke/project-management-in-google-sheets.html" rel="alternate"/><published>2017-12-16T08:00:00+03:00</published><updated>2017-12-16T08:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-12-16:/project-management-in-google-sheets.html</id><summary type="html">&lt;div class="section" id="outline-of-project"&gt;
&lt;h2&gt;Outline of Project&lt;/h2&gt;
&lt;p&gt;I wanted a google sheet file that could manage simple projects.
This meant that it could track tasks, send notifications when
tasks were late and differentiate done, undone and late tasks when
the file was opened and editted. To do this, I decided to research
into Google …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="outline-of-project"&gt;
&lt;h2&gt;Outline of Project&lt;/h2&gt;
&lt;p&gt;I wanted a google sheet file that could manage simple projects.
This meant that it could track tasks, send notifications when
tasks were late and differentiate done, undone and late tasks when
the file was opened and editted. To do this, I decided to research
into Google Sheets Scripts, which ended up being a powerful tool
that I could use to achieve my means.&lt;/p&gt;
&lt;div class="section" id="sending-notifications-for-late-tasks"&gt;
&lt;h3&gt;Sending notifications for Late Tasks&lt;/h3&gt;
&lt;p&gt;For this I first had to set a trigger. There are 2 methods of
doing this that I currently know of.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Using the menu bar by going to:
Edit &amp;gt; Current project's triggers &amp;gt; Add a new trigger&lt;/li&gt;
&lt;li&gt;Programmatically by creating a function and running it once.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I went with the programmatic way because this would enable me to
easier set it up on other sheets.&lt;/p&gt;
&lt;p&gt;So assuming there is a function called mainFunction, I write the
following trigger:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;createTimeDrivenTriggers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;ScriptApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mainFunction&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeBased&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;everyDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will run the function 'mainFunction' once per day. To
activate the trigger, click on Run &amp;gt; Run Function &amp;gt;
createTimeDrivenTriggers. The trigger can now be seen in the
triggers list menu. When running the trigger for the first time, a
page will pop up requesting for some permissions to be allowed.&lt;/p&gt;
&lt;p&gt;To send a mail using the script is also fairly easy. Since the
project sheet might have may participants, I set up a function
that sends emails to an array provided to it with a particular
message.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;MailApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The emails are set in a sheet called 'lookup'. So the script will
find this sheet and read the emails from it. The emails are stored
in a column named 'Emails'.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getEmailsToNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;emailCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getColumnByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PropertiesService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getScriptProperties&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;EMAILS_COLUMN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;emailCol&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For the script, the preconditions I set for it to be able to run
was that the first row should have the following names in the
various cells:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Features&lt;/li&gt;
&lt;li&gt;Status&lt;/li&gt;
&lt;li&gt;DateDue&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means that each sheet has to follow this pattern. To enforce this
I wrote the following script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getColumnByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getNotificationsFromSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getValues&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getColumnByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DateDue&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;featuresCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getColumnByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Features&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getColumnByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;featuresCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;error : Sheet does not follow expected format&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getLateDateDues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;featuresCol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// checkLateDateDues(dateDueCol, statusCol, featuresCol, data);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// return [&amp;#39;this is cool&amp;#39;, &amp;#39;this is another one&amp;#39;, &amp;#39;I love this&amp;#39;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The function getColumnByName checks the first row for any
columnName provided to it. If a columnName is not found it returns
-1. So in the function getNotificationsFromSheet, we check for the
3 cells, and if there is any that is missing and error is
returned.&lt;/p&gt;
&lt;p&gt;The getLateDateDues function just loops through all the dates
comparing them to the current date. If any date is late and its
status is not 'done', it adds this to the messages for alerting
and also colors that particular row red.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getLateDateDues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;featuresCol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// loop through the date due column only&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getValues&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dateNow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dateDue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rowRange&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateNow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dateDue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;done&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;featuresCol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; was due on &amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dateDue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;rowRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#ffcdd2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can find a copy of the complete gist &lt;a class="reference external" href="https://gist.github.com/jnduli/ad6ef7e12715c63a6d933368e0c61be0"&gt;here:late&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="changing-colors-while-editting"&gt;
&lt;h3&gt;Changing Colors while Editting&lt;/h3&gt;
&lt;p&gt;While editing the file, you also need to get some visual feedback
on deadlines and errors. To do this, google sheets provides simple
triggers that help out. For example, you can try this out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onEdit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;The sheet has been editted&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you save this, and edit any cell on the sheet, you will see
that message on the logger. To access the logger : View &amp;gt; Logs&lt;/p&gt;
&lt;p&gt;The first thing to check for is if the editted cell belongs to the
DateDue or status column. To do this, you need to get the
activeSheet and the DataRange.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onEdit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;activeSheet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getActiveSheet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sheetName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;activeSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;activeSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDataRange&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can get the column editted and row editted. Note that
e.range.getColumn() and e.range.getRow(), start their indexes at
1, so to work properly with arrays we need to subtract 1 from the
values we get.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;editTasksSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getValues&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;columnEditted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getColumn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rowEditted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;valueInput&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rowEditted&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;columnEditted&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getColumnByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DateDue&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getColumnByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;columnEditted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rowRange&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowEditted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// var dateInput = data[rowEditted][columnEditted];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;formatBasedOnDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowRange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;valueInput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;columnEditted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valueInput&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;done&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rowRange&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowEditted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;rowRange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#c8e6c9&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;formatBasedOnDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowRange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rowEditted&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From the above code snippet, we first look for the columns named
'DateDue' and 'Status'. If they are not existent, the script stops
working because the sheet is not properly formatted. Afterwards we just
format the sheet appropriately based off these rules:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;If the date input is older than the current date, color the row
red since it is a late task&lt;/li&gt;
&lt;li&gt;If date input is later than current task, reset the background
color to white.&lt;/li&gt;
&lt;li&gt;If status input is done, color the row green&lt;/li&gt;
&lt;li&gt;If status is something other than done, do the date formatting.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The completed file can be found in the following gist &lt;a class="reference external" href="https://gist.github.com/jnduli/ad6ef7e12715c63a6d933368e0c61be0"&gt;here:edit&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="projects"/></entry><entry><title>Prepare Kicad PCB for Elecrow Production</title><link href="https://blog.jnduli.co.ke/prepare-kicad-pcb-elecrow.html" rel="alternate"/><published>2017-12-07T08:00:00+03:00</published><updated>2017-12-07T08:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-12-07:/prepare-kicad-pcb-elecrow.html</id><summary type="html">&lt;p&gt;Before designing the PCB, set the following design rules:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Minimum PCB Track : greater than 0.2mm&lt;/li&gt;
&lt;li&gt;Minimum Track /Vias space: greater than 0.2mm&lt;/li&gt;
&lt;li&gt;Minimum pads space: greater than 0.2mm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The defaults provided by Kicad are OK, so no need to change them
unless you have some special requirements …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Before designing the PCB, set the following design rules:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Minimum PCB Track : greater than 0.2mm&lt;/li&gt;
&lt;li&gt;Minimum Track /Vias space: greater than 0.2mm&lt;/li&gt;
&lt;li&gt;Minimum pads space: greater than 0.2mm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The defaults provided by Kicad are OK, so no need to change them
unless you have some special requirements.&lt;/p&gt;
&lt;p&gt;Once the pcb has been completed, go go:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;File&amp;gt;&amp;gt;Plot
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make sure the following options are checked in Layers section:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;F.Cu&lt;/li&gt;
&lt;li&gt;B.Cu&lt;/li&gt;
&lt;li&gt;B.SilkS&lt;/li&gt;
&lt;li&gt;F.SilkS&lt;/li&gt;
&lt;li&gt;B.Mask&lt;/li&gt;
&lt;li&gt;F.Mask&lt;/li&gt;
&lt;li&gt;Edge.Cuts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make sure the Plot format is set to Gerber.
It is also advisable to set an OutputDirectory for your gerber
files. This prevents mixing up the gerber with normal project
files.&lt;/p&gt;
&lt;p&gt;Make sure the following are checked in Options:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Plot footprint values&lt;/li&gt;
&lt;li&gt;Plot footprint references&lt;/li&gt;
&lt;li&gt;Exclude PCB edge layer from other layers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For Gerber options, make sure this is checked:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Use Protel filename extensions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Click on Plot to generate the gerber files.&lt;/p&gt;
&lt;p&gt;To generate the drill files, click on &amp;quot;Generate Drill File&amp;quot;.
I set the Drill Units to Millimeters, Zeros Format to Decimal
Format and Dril Map File Format to Gerber. Also Drill Origin was
set to Absolute. Then click Drill File.&lt;/p&gt;
&lt;p&gt;Kicad outputs files with a different naming convention as that
expected by elecrow. So you'll have to rename these files. For
examples:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;pump-B.Cu.gbl becomes pump.gbl&lt;/li&gt;
&lt;li&gt;pump-B.Mask.gbs becomes pump.gbs&lt;/li&gt;
&lt;li&gt;pump-B.SilkS.gbo becomes pump.gbo&lt;/li&gt;
&lt;li&gt;pump-Edge.Cuts.gm1 becomes pump.gml&lt;/li&gt;
&lt;li&gt;pump-F.Cu.gtl becomes pump.gtl&lt;/li&gt;
&lt;li&gt;pump-F.Mask.gts becomes pump.gts&lt;/li&gt;
&lt;li&gt;pump-F.SilkS.gto becomes pump.gto&lt;/li&gt;
&lt;li&gt;pump.drl becomes pump.txt&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After renaming the files you can then compress all of them into a
zip file and make the order.&lt;/p&gt;
</content><category term="Engineering"/></entry><entry><title>ArchLinux Signature Error</title><link href="https://blog.jnduli.co.ke/archlinux-pacman-signature-error.html" rel="alternate"/><published>2017-11-30T20:00:00+03:00</published><updated>2017-11-30T20:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-11-30:/archlinux-pacman-signature-error.html</id><summary type="html">&lt;p&gt;When updating archlinux using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-Syu
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I sometimes get an error message that looks something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;error:&lt;span class="w"&gt; &lt;/span&gt;zstd:&lt;span class="w"&gt; &lt;/span&gt;signature&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Andrzej Giniewicz (giniu) &amp;lt;randomemail@gmail.com&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;marginal&lt;span class="w"&gt; &lt;/span&gt;trust
::&lt;span class="w"&gt; &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;/var/cache/pacman/pkg/zstd-1.3.2-1-x86_64.pkg.tar.xz&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;corrupted&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;invalid&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;corrupted&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;PGP&lt;span class="w"&gt; &lt;/span&gt;signature …&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;When updating archlinux using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-Syu
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I sometimes get an error message that looks something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;error:&lt;span class="w"&gt; &lt;/span&gt;zstd:&lt;span class="w"&gt; &lt;/span&gt;signature&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Andrzej Giniewicz (giniu) &amp;lt;randomemail@gmail.com&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;marginal&lt;span class="w"&gt; &lt;/span&gt;trust
::&lt;span class="w"&gt; &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;/var/cache/pacman/pkg/zstd-1.3.2-1-x86_64.pkg.tar.xz&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;corrupted&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;invalid&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;corrupted&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;PGP&lt;span class="w"&gt; &lt;/span&gt;signature&lt;span class="o"&gt;))&lt;/span&gt;.
Do&lt;span class="w"&gt; &lt;/span&gt;you&lt;span class="w"&gt; &lt;/span&gt;want&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;delete&lt;span class="w"&gt; &lt;/span&gt;it?&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;Y/n&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Y
error:&lt;span class="w"&gt; &lt;/span&gt;failed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;transaction&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;invalid&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;corrupted&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;PGP&lt;span class="w"&gt; &lt;/span&gt;signature&lt;span class="o"&gt;))&lt;/span&gt;
Errors&lt;span class="w"&gt; &lt;/span&gt;occurred,&lt;span class="w"&gt; &lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;packages&lt;span class="w"&gt; &lt;/span&gt;were&lt;span class="w"&gt; &lt;/span&gt;upgraded.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pacman uses a collection of PGP keys which check signed packages
and databases. If a key is corrupted or invalid, a package cannot
be installed or updated. In the example presented above, the
package zstd prevented my whole system from getting upgraded.&lt;/p&gt;
&lt;p&gt;To fix this, you try to update the keys using the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-Sy&lt;span class="w"&gt; &lt;/span&gt;archlinux-keyring
sudo&lt;span class="w"&gt; &lt;/span&gt;pacman-key&lt;span class="w"&gt; &lt;/span&gt;--populate&lt;span class="w"&gt; &lt;/span&gt;archlinux
sudo&lt;span class="w"&gt; &lt;/span&gt;pacman-key&lt;span class="w"&gt; &lt;/span&gt;--refresh-keys
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The source for this fix is from &lt;a class="reference external" href="https://forum.manjaro.org/t/cant-update-signature-from-andrzej-giniewicz-giniu-gginiu-gmail-com-is-marginal-trust/33259"&gt;here:source&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>Using Pass - A Password Manager/Generator</title><link href="https://blog.jnduli.co.ke/password-manager-pass.html" rel="alternate"/><published>2017-11-16T14:00:00+03:00</published><updated>2017-11-16T14:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-11-16:/password-manager-pass.html</id><summary type="html">&lt;p&gt;Pass is a password manager that stores passwords locally on the
host machine. Since the passwords are stored locally there is
minimal risk on your passwords being exposed after some data
breach occurring. Also, you can use git to version control the
passwords, and set them up in a repo …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Pass is a password manager that stores passwords locally on the
host machine. Since the passwords are stored locally there is
minimal risk on your passwords being exposed after some data
breach occurring. Also, you can use git to version control the
passwords, and set them up in a repo on any machine.&lt;/p&gt;
&lt;p&gt;To install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;pass
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then to initialize the password store:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pass&lt;span class="w"&gt; &lt;/span&gt;init&lt;span class="w"&gt; &lt;/span&gt;email
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To insert a password into the store:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pass&lt;span class="w"&gt; &lt;/span&gt;insert&lt;span class="w"&gt; &lt;/span&gt;/email/email@dns.com
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you get  the following error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;gpg:&lt;span class="w"&gt; &lt;/span&gt;email@dns.com:&lt;span class="w"&gt; &lt;/span&gt;skipped:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;public&lt;span class="w"&gt; &lt;/span&gt;key
gpg:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;stdin&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;encryption&lt;span class="w"&gt; &lt;/span&gt;failed:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;public&lt;span class="w"&gt; &lt;/span&gt;key
Password&lt;span class="w"&gt; &lt;/span&gt;encryption&lt;span class="w"&gt; &lt;/span&gt;aborted.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then you have to first generate the gpg keys:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;gpg&lt;span class="w"&gt; &lt;/span&gt;--full-gen-key
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will take you through the process step by step. All someone
has to do is follow the prompts.&lt;/p&gt;
&lt;p&gt;To generate a password, do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pass&lt;span class="w"&gt; &lt;/span&gt;generate&lt;span class="w"&gt; &lt;/span&gt;name/of/service&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which will generate a password 10 characters long&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pass&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;generate&lt;span class="w"&gt; &lt;/span&gt;name/of/service&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;will generate password without special symbols i.e. only
alphanumeric characters.&lt;/p&gt;
&lt;p&gt;To edit or overwrite password&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;password&lt;span class="w"&gt; &lt;/span&gt;edit&lt;span class="w"&gt; &lt;/span&gt;name/of/service&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;pass&lt;span class="w"&gt; &lt;/span&gt;inserte
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Other commands include:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pass&lt;span class="w"&gt; &lt;/span&gt;name/of/service&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# displays the password&lt;/span&gt;
pass&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;name/of/service&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# copies the password to xclip&lt;/span&gt;

pass&lt;span class="w"&gt; &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;name/of/sercie&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# removes password&lt;/span&gt;
pass&lt;span class="w"&gt; &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# removes full directory&lt;/span&gt;

pass&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;init&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# sets up git in pass folder&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To find out more about pass, you can check &lt;a class="reference external" href="https://www.passwordstore.org/"&gt;here&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>Keeping a Diary in Vim</title><link href="https://blog.jnduli.co.ke/keeping-diary-in-vim.html" rel="alternate"/><published>2017-11-05T09:00:00+03:00</published><updated>2017-11-05T09:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-11-05:/keeping-diary-in-vim.html</id><summary type="html">&lt;p&gt;A diary is a good way to write down one's thoughts and memories of
the day.&lt;/p&gt;
&lt;p&gt;Being a vim fan, I had to find a way to easily help me write down
my diary. This is where vim wiki comes in. It is basically a means
of writing down wikis …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A diary is a good way to write down one's thoughts and memories of
the day.&lt;/p&gt;
&lt;p&gt;Being a vim fan, I had to find a way to easily help me write down
my diary. This is where vim wiki comes in. It is basically a means
of writing down wikis in vim, and has an awesome diary mode.&lt;/p&gt;
&lt;p&gt;I use vundle as my vim plugin manager. So to install vimwiki, I
added to the following to my vimrc file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Plugin &lt;span class="s1"&gt;&amp;#39;vimwiki/vimwiki&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then ran the following from withing vim (while the vimrc file
is the current buffer):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;source %
&lt;span class="p"&gt;:&lt;/span&gt;PluginInstall
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To enter diary mode, I just type &amp;lt;leader&amp;gt;wi in any vim session and
it will direct me into the diary entries.&lt;/p&gt;
&lt;p&gt;To add a diary on the day's happenings, I just type
&amp;lt;leader&amp;gt;w&amp;lt;leader&amp;gt;w and it will open a blank buffer. When this is
saved it will be a new day's entry.&lt;/p&gt;
&lt;p&gt;To update the diary with the new entry, &amp;lt;leader&amp;gt;wi will take you
to the page containing the various entries. Then type
&amp;lt;leader&amp;gt;w&amp;lt;leader&amp;gt;i and this will update the list with the new
entry.&lt;/p&gt;
&lt;p&gt;Since I use vim a lot, I find this really useful when collecting
my thoughts during a day.&lt;/p&gt;
&lt;p&gt;So in summary these are the commands helpful for vimwiki diary
mode:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;w&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;w&lt;/span&gt; &lt;span class="c"&gt;&amp;quot; create new diary note for the day&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;wi&lt;/span&gt; &lt;span class="c"&gt;&amp;quot; show all diary entries&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;w&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;i&lt;/span&gt; &lt;span class="c"&gt;&amp;quot; update entries&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"/><category term="vim"/></entry><entry><title>Scrolling Text With 5*4 LED Array</title><link href="https://blog.jnduli.co.ke/5-by-4-led-array-scrolling-text.html" rel="alternate"/><published>2017-10-29T10:20:00+03:00</published><updated>2017-10-29T10:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-10-29:/5-by-4-led-array-scrolling-text.html</id><summary type="html">&lt;p&gt;I usually see lights in Nairobi scrolling text from right to left.
It is an interesting thing to see, and if done right is usually
beautiful. I wanted to make one, and so this is how I went about
it.&lt;/p&gt;
&lt;div class="section" id="multiplexing-leds"&gt;
&lt;h2&gt;Multiplexing LEDs&lt;/h2&gt;
&lt;p&gt;To light and LED one needs 5V supplied …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I usually see lights in Nairobi scrolling text from right to left.
It is an interesting thing to see, and if done right is usually
beautiful. I wanted to make one, and so this is how I went about
it.&lt;/p&gt;
&lt;div class="section" id="multiplexing-leds"&gt;
&lt;h2&gt;Multiplexing LEDs&lt;/h2&gt;
&lt;p&gt;To light and LED one needs 5V supplied to cathode and GND supplied
to anode. This means if we have 2 leds, both receiving 5V and only
one receiving GND, only one LED will light. The same occurs when
both receive GND and only one receives 5V. This is the basic
building block of an LED matrix.&lt;/p&gt;
&lt;p&gt;So how does one keep this so. Well, one option is using a
microcontroller. The microcontroller's pins can be set to output a
HIGH (5V) or a LOW(GND/0V). So having a microcontroller will help
us out in choosing which LED to use.&lt;/p&gt;
&lt;p&gt;The following is the schematic I then came up with:&lt;/p&gt;
&lt;img alt="5_by_4 led array image" src="https://blog.jnduli.co.ke/images/5_by_4_led_array.png" /&gt;
&lt;p&gt;To have the scrolling effect, I then wrote code that turns on and
off LEDs at a particular pattern. Making this faster will result
in less flickering of light. I used an atmega 8 for this and added
the respective current limiting resistors. The circuit and code
for this can be found &lt;a class="reference external" href="https://github.com/jnduli/led_array_atmega8"&gt;here:githublink&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is the image of the final fabricated circuit:&lt;/p&gt;
&lt;img alt="5_by_4 led array image" src="https://blog.jnduli.co.ke/images/5_by_4_led_physical_circuit.jpg" /&gt;
&lt;p&gt;You can find the video of the working circuit here. The text being
shown is &amp;quot;HAPPY EASTER&amp;quot; in case it is the video is not clear
enough.&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/Zk5a-tJbTKo" frameborder="0" gesture="media" allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
</content><category term="Engineering"/><category term="avr"/><category term="projects"/></entry><entry><title>I3 Window Manager</title><link href="https://blog.jnduli.co.ke/i3-window-manager.html" rel="alternate"/><published>2017-10-21T08:00:00+03:00</published><updated>2017-10-21T08:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-10-21:/i3-window-manager.html</id><summary type="html">&lt;p&gt;I've been using xfce4 as my primary window manager for some time
now. Its pretty light weight and works really well on my laptop.
I sometimes use an Acer D270 with 2GB Ram and 1.6Ghz processor,
which is weak.&lt;/p&gt;
&lt;p&gt;However, I decided I wanted to try out something new …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been using xfce4 as my primary window manager for some time
now. Its pretty light weight and works really well on my laptop.
I sometimes use an Acer D270 with 2GB Ram and 1.6Ghz processor,
which is weak.&lt;/p&gt;
&lt;p&gt;However, I decided I wanted to try out something new. I'd never
actually used another window manager in linux apart from the
defaults provided by various distros and xfce4 ( which I always
install). So I did some digging around and found i3.&lt;/p&gt;
&lt;p&gt;i3 is a tiling window manager, and my current default window
manager too. I don't know if its the greatest one or even a good
one. It was just the first other window manager I tried after
xfce4 and I liked it a lot. In fact, I liked it so much that I
haven't tried tinkering with another window manager yet.&lt;/p&gt;
&lt;p&gt;To install i3 in archlinux:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;i3wm&lt;span class="w"&gt; &lt;/span&gt;i3lock&lt;span class="w"&gt; &lt;/span&gt;i3status&lt;span class="w"&gt; &lt;/span&gt;dmenu
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The default i3 config file works but I had to make some of my
changes.&lt;/p&gt;
&lt;p&gt;First off, I really like the xfce4-terminal, so I wanted to still
use it as my default terminal. This terminal also has a drop-down
feature which I use a lot, so I also had to figure out a way to do
this. So this was my change to support this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+Return&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xfce4-terminal
&lt;span class="c1"&gt;# xfce4 dropdown terminal&lt;/span&gt;
bindsym&lt;span class="w"&gt; &lt;/span&gt;F12&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xfce4-terminal&lt;span class="w"&gt; &lt;/span&gt;--drop-down
for_window&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;xfce4-terminal&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;floating&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since I'm a dedicated vim user, I also had to find a way to
customize i3 to work similarly to vim.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# change focus&lt;/span&gt;
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+h&lt;span class="w"&gt; &lt;/span&gt;focus&lt;span class="w"&gt; &lt;/span&gt;left
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+j&lt;span class="w"&gt; &lt;/span&gt;focus&lt;span class="w"&gt; &lt;/span&gt;down
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+k&lt;span class="w"&gt; &lt;/span&gt;focus&lt;span class="w"&gt; &lt;/span&gt;up
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+l&lt;span class="w"&gt; &lt;/span&gt;focus&lt;span class="w"&gt; &lt;/span&gt;right

&lt;span class="c1"&gt;# move focused window&lt;/span&gt;
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+Shift+h&lt;span class="w"&gt; &lt;/span&gt;move&lt;span class="w"&gt; &lt;/span&gt;left
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+Shift+j&lt;span class="w"&gt; &lt;/span&gt;move&lt;span class="w"&gt; &lt;/span&gt;down
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+Shift+k&lt;span class="w"&gt; &lt;/span&gt;move&lt;span class="w"&gt; &lt;/span&gt;up
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+Shift+l&lt;span class="w"&gt; &lt;/span&gt;move&lt;span class="w"&gt; &lt;/span&gt;right
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are also some custom applications I use, and that I wanted
to start up with i3. An example is redshift. To do that I just
added this to the config file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# redshift&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--no-startup-id&lt;span class="w"&gt; &lt;/span&gt;redshift-gtk
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To take a screenshot, I decided to use scrot. Here is my addition
to i3 for that.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# scrot screen shot&lt;/span&gt;
bindsym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mod&lt;/span&gt;+p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;scrot ~/Downloads/Screenshot%Y-%m-%d%H:%M:%S.png&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To change the desktop wallpater, I decided to use feh.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# background image&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;feh&lt;span class="w"&gt; &lt;/span&gt;--bg-scale&lt;span class="w"&gt; &lt;/span&gt;~/Pictures/i3_solarized.png
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To use i3lock, add the following to the config:
.. code-block:: bash&lt;/p&gt;
&lt;blockquote&gt;
#setting up i3lock
exec --no-startup-id xautolock -time 1 -locker 'i3lock -n'&lt;/blockquote&gt;
&lt;p&gt;I'll be making a lot of more changes to my i3 config file. To
checkout what I've implemented or changed you can view the latest
config file &lt;a class="reference external" href="https://github.com/jnduli/dotfiles/blob/master/i3config"&gt;here&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"/><category term="window-managers"/></entry><entry><title>Disabling Blanking in Raspberry Pi</title><link href="https://blog.jnduli.co.ke/disabling-blanking-raspberry-pi.html" rel="alternate"/><published>2017-10-17T15:00:00+03:00</published><updated>2017-10-17T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-10-17:/disabling-blanking-raspberry-pi.html</id><summary type="html">&lt;p&gt;Blanking is whereby a screen just goes blank (i.e. black screen).
This usually happens after some time of no usage on the raspberry
pi which is about 15 minutes. This can sometimes become
frustrating especially if it is a screen set up for monitoring
something.&lt;/p&gt;
&lt;p&gt;So to disable it …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Blanking is whereby a screen just goes blank (i.e. black screen).
This usually happens after some time of no usage on the raspberry
pi which is about 15 minutes. This can sometimes become
frustrating especially if it is a screen set up for monitoring
something.&lt;/p&gt;
&lt;p&gt;So to disable it temporarily:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;xset&lt;span class="w"&gt; &lt;/span&gt;s&lt;span class="w"&gt; &lt;/span&gt;off&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# disables screen saver&lt;/span&gt;
xset&lt;span class="w"&gt; &lt;/span&gt;-dpms&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#disable power management settings&lt;/span&gt;
xset&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;noblank
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To disable it permanently, open the file
/etc/lightdm/lightdm.conf:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;vi&lt;span class="w"&gt; &lt;/span&gt;/etc/lightdm/lightdm.conf
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then add the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;xserver-command&lt;span class="o"&gt;=&lt;/span&gt;X&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-dpms
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Engineering"/><category term="raspberry pi"/></entry><entry><title>GRUB RESCUE FiX</title><link href="https://blog.jnduli.co.ke/grub_rescue_fix.html" rel="alternate"/><published>2017-09-21T15:00:00+03:00</published><updated>2017-09-21T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-09-21:/grub_rescue_fix.html</id><summary type="html">&lt;p&gt;So I found myself in windows some time this week, and it started
updating. The process had one major consequence, grub could not
discover my linux partition, and so brought me to a prompt
containing 'grub_rescue'.&lt;/p&gt;
&lt;p&gt;To fix this, I first did:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ls
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will show a list of the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;So I found myself in windows some time this week, and it started
updating. The process had one major consequence, grub could not
discover my linux partition, and so brought me to a prompt
containing 'grub_rescue'.&lt;/p&gt;
&lt;p&gt;To fix this, I first did:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ls
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will show a list of the partitions of my hard drive,
something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;hd0&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;hd0,gpt2&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;hd0,gpt3&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;hd0,gpt4&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I needed to get the partition with my linux on it. So to do this I
did:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;hd0,gpt2&lt;span class="o"&gt;)&lt;/span&gt;/
ls&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;hd0,gpt3&lt;span class="o"&gt;)&lt;/span&gt;/
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While doing this, I was looking for a partition that has folders
similar to those in root. So when I got a partition that has
bin, boot, home, lib, etc in it, I knew I had got the correct one.&lt;/p&gt;
&lt;p&gt;Assuming its (hd0,gpt3), I then did:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;hd0,gpt3&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;hd0,gpt3&lt;span class="o"&gt;)&lt;/span&gt;/boot/grub
insmod&lt;span class="w"&gt; &lt;/span&gt;normal
normal
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this, I was able to load the normal grub menu and boot into
archlinux.&lt;/p&gt;
&lt;p&gt;Tox this permanently:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;/dev/sda1&lt;span class="w"&gt; &lt;/span&gt;/boot/efi
sudo&lt;span class="w"&gt; &lt;/span&gt;grub-install&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-efi&lt;span class="w"&gt; &lt;/span&gt;--efi-directory&lt;span class="o"&gt;=&lt;/span&gt;/boot/efi&lt;span class="w"&gt; &lt;/span&gt;--bootloader-id&lt;span class="o"&gt;=&lt;/span&gt;grub
sudo&lt;span class="w"&gt; &lt;/span&gt;grub-mkconfig&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;/boot/grub/grub.cfg
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is just from my steps on installation of archlinux on my asus
laptop found &lt;a class="reference external" href="https://blog.jnduli.co.ke/asus-zenbook-archlinux-setup.html"&gt;here&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>Asus Zenbook Keyboard &amp; Screen Brightness Fix On i3</title><link href="https://blog.jnduli.co.ke/asus-zenbook-keyboard-screen-issues-fix.html" rel="alternate"/><published>2017-09-01T14:00:00+03:00</published><updated>2017-09-01T14:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-09-01:/asus-zenbook-keyboard-screen-issues-fix.html</id><summary type="html">&lt;div class="section" id="keyboard-backlight-fix"&gt;
&lt;h2&gt;Keyboard backlight fix&lt;/h2&gt;
&lt;p&gt;Source for this information can be found &lt;a class="reference external" href="https://wiki.archlinux.org/index.php/Keyboard_backlight"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The link has a file called kb-light.py. I set up this file in
/usr/local/bin.&lt;/p&gt;
&lt;p&gt;I then opened my i3config file and added the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;bindsym XF86KbdBrightnessUp exec python &lt;span class="sr"&gt;/usr/&lt;/span&gt;local&lt;span class="sr"&gt;/bin/&lt;/span&gt;kb&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;light&lt;/span&gt;.&lt;span class="k"&gt;py&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
bindsym XF86KbdBrightnessDown …&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="section" id="keyboard-backlight-fix"&gt;
&lt;h2&gt;Keyboard backlight fix&lt;/h2&gt;
&lt;p&gt;Source for this information can be found &lt;a class="reference external" href="https://wiki.archlinux.org/index.php/Keyboard_backlight"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The link has a file called kb-light.py. I set up this file in
/usr/local/bin.&lt;/p&gt;
&lt;p&gt;I then opened my i3config file and added the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;bindsym XF86KbdBrightnessUp exec python &lt;span class="sr"&gt;/usr/&lt;/span&gt;local&lt;span class="sr"&gt;/bin/&lt;/span&gt;kb&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;light&lt;/span&gt;.&lt;span class="k"&gt;py&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
bindsym XF86KbdBrightnessDown exec python &lt;span class="sr"&gt;/usr/&lt;/span&gt;local&lt;span class="sr"&gt;/bin/&lt;/span&gt;kb&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;light&lt;/span&gt;.&lt;span class="k"&gt;py&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now when I press the keyboard brightness up and down key, the
keyboard lights change as expected.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="screen-brightness-fix"&gt;
&lt;h2&gt;Screen brightness fix&lt;/h2&gt;
&lt;p&gt;For this I wanted to use xbacklight. The problem I got was that
when I tried&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;xbacklight &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;inc&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I got the error &amp;quot;No outputs have backlight propery&amp;quot;.&lt;/p&gt;
&lt;p&gt;To fix this, I installed the intel driver&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo pacman &lt;span class="p"&gt;-&lt;/span&gt;S xf86&lt;span class="p"&gt;-&lt;/span&gt;video&lt;span class="p"&gt;-&lt;/span&gt;intel
&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;And after rebooting it worked well.
So to set up the keyboard keys for screen brightness, I added this to my i3 config file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;bindsym XF86MonBrightnessUp exec xbacklight &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;inc&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; # increase screen brightness
bindsym XF86MonBrightnessDown exec xbacklight &lt;span class="p"&gt;-&lt;/span&gt;dec &lt;span class="m"&gt;10&lt;/span&gt; # decrease screen brightness
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="media-keys-usage-fix"&gt;
&lt;h2&gt;Media Keys Usage Fix&lt;/h2&gt;
&lt;p&gt;For this, I first had to install pulseaudio.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo pacman &lt;span class="p"&gt;-&lt;/span&gt;S pulseaudio
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then I added this to my i3 config files:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;bindsym XF86AudioRaiseVolume exec &lt;span class="p"&gt;--&lt;/span&gt;no&lt;span class="p"&gt;-&lt;/span&gt;startup&lt;span class="p"&gt;-&lt;/span&gt;id pactl &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;sink&lt;span class="p"&gt;-&lt;/span&gt;volume &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;% #increase sound volume
bindsym XF86AudioLowerVolume exec &lt;span class="p"&gt;--&lt;/span&gt;no&lt;span class="p"&gt;-&lt;/span&gt;startup&lt;span class="p"&gt;-&lt;/span&gt;id pactl &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;sink&lt;span class="p"&gt;-&lt;/span&gt;volume &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;-5&lt;/span&gt;% #decrease sound volume
bindsym XF86AudioMute exec &lt;span class="p"&gt;--&lt;/span&gt;no&lt;span class="p"&gt;-&lt;/span&gt;startup&lt;span class="p"&gt;-&lt;/span&gt;id pactl &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;sink&lt;span class="p"&gt;-&lt;/span&gt;mute &lt;span class="m"&gt;0&lt;/span&gt; toggle # mute sound
&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now audio can be increased / decreased using my media keys.&lt;/p&gt;
&lt;p&gt;My i3 config file can be found &lt;a class="reference external" href="https://github.com/jnduli/dotfiles"&gt;here:i3_config_file&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>My First Vim Function</title><link href="https://blog.jnduli.co.ke/my-first-vim-function.html" rel="alternate"/><published>2017-08-09T08:20:00+03:00</published><updated>2017-08-09T08:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-08-09:/my-first-vim-function.html</id><summary type="html">&lt;p&gt;I finally got down to writing my first vim function. It was a
gruelling journey but I finally got through it. So I'll write down
the problem I had and the fix I finally came up with as my
solution.&lt;/p&gt;
&lt;div class="section" id="problem-statement"&gt;
&lt;h2&gt;Problem Statement&lt;/h2&gt;
&lt;p&gt;I usually keep a to do list of …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I finally got down to writing my first vim function. It was a
gruelling journey but I finally got through it. So I'll write down
the problem I had and the fix I finally came up with as my
solution.&lt;/p&gt;
&lt;div class="section" id="problem-statement"&gt;
&lt;h2&gt;Problem Statement&lt;/h2&gt;
&lt;p&gt;I usually keep a to do list of things I should do during the day
and week. Over time, tasks get lost as I remove some lines and I
can't keep a track of my progress in terms of planning and
implementation.
So basically I wanted a means for later on in the year or in my
life, I could have a file that showed how much I planned and how
much I had achieved.&lt;/p&gt;
&lt;p&gt;So I created the file. It had the following syntax. I use vimwiki,
so to generate the table I just type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;VimwikiTable &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The file looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; Week &lt;span class="p"&gt;|&lt;/span&gt; Total &lt;span class="p"&gt;|&lt;/span&gt; Achieved &lt;span class="p"&gt;|&lt;/span&gt; %    &lt;span class="p"&gt;|&lt;/span&gt; Comments                        &lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="p"&gt;|------|-------|----------|------|---------------------------------|&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;13&lt;/span&gt;    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;.&lt;span class="m"&gt;69&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; setting &lt;span class="k"&gt;up&lt;/span&gt; lap  took &lt;span class="k"&gt;up&lt;/span&gt; time    &lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;        &lt;span class="p"&gt;|&lt;/span&gt;      &lt;span class="p"&gt;|&lt;/span&gt;                                 &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This table has a percentage column that I wanted to be
automatically calculated. This would provide a means of checking
whether I'm becoming better at goal setting and goal achievement
over time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="implementation"&gt;
&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;p&gt;To get the percentage, I had to basically get the row value that
corresponded to total, and the row value that corresponded to
achieved.&lt;/p&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;To get the once corresponding to totaL, I did this in normal mode:&lt;/dt&gt;
&lt;dd&gt;^3wviw&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;What this does is this:&lt;/p&gt;
&lt;blockquote&gt;
^ goes to beginning of line
3w goes 3 words ahead after going to beginning of line
viw selects the current word, which happens to be the total&lt;/blockquote&gt;
&lt;p&gt;With this I had the number in total column selected, so I had to
find out how to store the number for later use. Thats when
registers came into play. So adding:&lt;/p&gt;
&lt;blockquote&gt;
&amp;quot;py&lt;/blockquote&gt;
&lt;p&gt;Will yank the selected word and store it in the named register p.
With this I can get the variable from the register. So to get the
number 13 in the first row, this was the function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;TodoPercentage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;normal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;viw&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;py&lt;/span&gt;
&lt;span class="s2"&gt;    let total = str2float(getreg(&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;p&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;))&lt;/span&gt;
&lt;span class="s2"&gt;endfunction&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The getreg() function just gets the values stored in a register,
and the str2float function converts a string to a float variable.&lt;/p&gt;
&lt;p&gt;To get the achieved value, I also did the same.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; TodoPercentage&lt;span class="p"&gt;()&lt;/span&gt;
    normal ^&lt;span class="m"&gt;3&lt;/span&gt;wviw&amp;quot;&lt;span class="k"&gt;py&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; total &lt;span class="p"&gt;=&lt;/span&gt; str2float&lt;span class="p"&gt;(&lt;/span&gt;getreg&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;p&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    normal ^&lt;span class="m"&gt;5&lt;/span&gt;wviw&amp;quot;&lt;span class="k"&gt;py&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; achieved &lt;span class="p"&gt;=&lt;/span&gt; str2float&lt;span class="p"&gt;(&lt;/span&gt;getreg&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;p&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since I had these two variables, I could now do the arithmetic.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; percentage &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;achieved/total&lt;span class="p"&gt;)&lt;/span&gt; * &lt;span class="m"&gt;100&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And since I just wanted to display the number in maximum of 2
decimal places, I used printf command, which sets the variable to
2 decimal places and also saves it in the per variable as a
string.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; per &lt;span class="p"&gt;=&lt;/span&gt; printf&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%.2f&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; percentage&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To display the number in the appropriate section, I decided to use
the execute command. This would execute the string, converting
special characters to vim commands e.g. &amp;lt;esc&amp;gt; to actually
pressing escape. The &amp;quot;normal!&amp;quot; executes the commands in normal
mode, the ! eliminates the custom mappings made.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;execute &lt;span class="s2"&gt;&amp;quot;normal! ^6wa &amp;quot;&lt;/span&gt;.per.&lt;span class="s2"&gt;&amp;quot;\&amp;lt;esc&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;After the &amp;quot;normal!&amp;quot; the following happens:&lt;/dt&gt;
&lt;dd&gt;^6w : moves to the start of the line, then 6 words after
a : appends characters, enter insert mode
.per. : concatenates the percentage string. Thus it will be
typed character by character
&amp;quot;&amp;lt;esc&amp;gt;&amp;quot; : initiates the esc sequence leaving insert mode. The
is used to signify that the key ESC is what is meant and not
the actual characters.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;So at the end of it all this was my function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; TodoPercentage&lt;span class="p"&gt;()&lt;/span&gt;
    normal ^&lt;span class="m"&gt;3&lt;/span&gt;wviw&amp;quot;&lt;span class="k"&gt;py&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; total &lt;span class="p"&gt;=&lt;/span&gt; str2float&lt;span class="p"&gt;(&lt;/span&gt;getreg&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;p&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    normal ^&lt;span class="m"&gt;5&lt;/span&gt;wviw&amp;quot;&lt;span class="k"&gt;py&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; achieved &lt;span class="p"&gt;=&lt;/span&gt; str2float&lt;span class="p"&gt;(&lt;/span&gt;getreg&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;p&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; percentage &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;achieved / total&lt;span class="p"&gt;)&lt;/span&gt; * &lt;span class="m"&gt;100&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; per &lt;span class="p"&gt;=&lt;/span&gt; printf&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%.2f&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; percentage&lt;span class="p"&gt;)&lt;/span&gt;
    execute &lt;span class="s2"&gt;&amp;quot;normal! ^6wa &amp;quot;&lt;/span&gt;.per.&lt;span class="s2"&gt;&amp;quot;\&amp;lt;esc&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now to run this function I decided to map it to &amp;lt;leader&amp;gt;cp meaning
calculate percentage.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;autocmd &lt;span class="nb"&gt;FileType&lt;/span&gt; vimwiki &lt;span class="nb"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;cp&lt;/span&gt; :&lt;span class="k"&gt;call&lt;/span&gt; TodoPercentage&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Cr&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can find this function implemented in my .vimrc file &lt;a class="reference external" href="https://github.com/jnduli/dotfiles"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="vim"/><category term="programming"/></entry><entry><title>Setting Up Raspberry Pi</title><link href="https://blog.jnduli.co.ke/setting-up-raspberry-pi.html" rel="alternate"/><published>2017-07-16T08:20:00+03:00</published><updated>2017-07-16T08:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-07-16:/setting-up-raspberry-pi.html</id><summary type="html">&lt;p&gt;The raspberry pi is a mini computer with GPIO pins that can be
used to interface with various sensors and actuators. More
information of the raspberry pi can be found &lt;a class="reference external" href="https://www.raspberrypi.org/"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The SD card should be of a size greater than 4GB, especially if
you want to install Raspbian Jesse …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The raspberry pi is a mini computer with GPIO pins that can be
used to interface with various sensors and actuators. More
information of the raspberry pi can be found &lt;a class="reference external" href="https://www.raspberrypi.org/"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The SD card should be of a size greater than 4GB, especially if
you want to install Raspbian Jesse.&lt;/p&gt;
&lt;p&gt;Connect the card to your computer and get its id. To do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;fdisk&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you do the above command before inserting the card and after
inserting the card, you'll find a new addition which is the card.&lt;/p&gt;
&lt;p&gt;Format the card to fat partition. To do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;umount&lt;span class="w"&gt; &lt;/span&gt;/dev/sdcardfound
sudo&lt;span class="w"&gt; &lt;/span&gt;mkfs.fat&lt;span class="w"&gt; &lt;/span&gt;/dev/sdcardfound
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After this the sd card is ready for use.&lt;/p&gt;
&lt;p&gt;Download the OS from
&lt;a class="reference external" href="https://www.raspberrypi.org/downloads/raspbian/"&gt;here:raspbian&lt;/a&gt;,
and unzip it. I chose Raspbian Jesse with Desktop for my OS.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;unzip&lt;span class="w"&gt; &lt;/span&gt;downloadedraspbian.zip
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then burn the OS into the sd card using dd:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;dd&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;unzippedraspbian.img&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sdcardfound&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4M&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;progress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once this step is completed the OS is ready for use.&lt;/p&gt;
&lt;div class="section" id="with-screen-keyboard-and-mouse"&gt;
&lt;h2&gt;With Screen, Keyboard and Mouse&lt;/h2&gt;
&lt;p&gt;Attach the sd card, screen, keyboard and mouse to the raspberry
pi. For power, a supply rated 5V 2.5A is recommended. In my case,
I used one rate 5V and 1A and it worked well. When powered, there
are two LED lights, a red one and a green one. The red should be
on indicating the pi is receiving power. The green light should be
blinking. If it is not this indicated either a problem with the sd
card or the power supply.&lt;/p&gt;
&lt;p&gt;Once the pi is started, wait until the desktop environment is
loaded. Then you can then enable vnc and ssh.&lt;/p&gt;
&lt;p&gt;To do this, go to the terminal and type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;raspi-config
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go to interface and enable both vnc and ssh.&lt;/p&gt;
&lt;p&gt;You can also go to MENU &amp;gt; PREFERENCES &amp;gt; Interfaces. From this you
can also enable ssh and vnc.&lt;/p&gt;
&lt;p&gt;To set up a virtual keyboard, first connect to a wifi/LAN network
and do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;update
sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;matchbox-keyboard
sudo&lt;span class="w"&gt; &lt;/span&gt;reboot
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The keyboard should be in accessibility menu.
If it isn't go to MENU &amp;gt; Preferences &amp;gt; Main Menu Editor &amp;gt;
Accesorites. Disable and enable the Keyboard option.&lt;/p&gt;
&lt;p&gt;To ssh into the pi, first get the ip address. To do this, hover on
the wifi icon and the ip will be displayed. You can also get the
ip address from the terminal by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ip&lt;span class="w"&gt; &lt;/span&gt;address&lt;span class="w"&gt; &lt;/span&gt;show
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From another computer, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ssh&lt;span class="w"&gt; &lt;/span&gt;pi@piipaddress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The password is : raspberry&lt;/p&gt;
&lt;p&gt;The pi already comes with a vnc server known as realvnc. So just
install the viewer on your laptop and use it. For archlinux:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;yaourt&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;realvnc-vnc-viewer
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then confirm that vnc is enabled on the pi. To use it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;vncviewer&lt;span class="w"&gt; &lt;/span&gt;piipaddress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Realvnc can also be setup to run via the cloud. Just visit their
website &lt;a class="reference external" href="https://www.realvnc.com/en/"&gt;here:realvnc&lt;/a&gt; to find out
how.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Engineering"/><category term="raspberry pi"/></entry><entry><title>ASUS ZenBook UX330UA ArchLinux Setup</title><link href="https://blog.jnduli.co.ke/asus-zenbook-archlinux-setup.html" rel="alternate"/><published>2017-06-28T15:00:00+03:00</published><updated>2017-06-28T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-06-28:/asus-zenbook-archlinux-setup.html</id><summary type="html">&lt;p&gt;I recently got the ASUS ZenBook UX330UA-AH54, which is a really
awesome machine. I've been using it for one month now, and its
beautiful.&lt;/p&gt;
&lt;p&gt;So first thing I did with the laptop was install archlinux (dual
boot with windows). These are the steps I took to set up
archlinux. Most …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I recently got the ASUS ZenBook UX330UA-AH54, which is a really
awesome machine. I've been using it for one month now, and its
beautiful.&lt;/p&gt;
&lt;p&gt;So first thing I did with the laptop was install archlinux (dual
boot with windows). These are the steps I took to set up
archlinux. Most of these steps can be found in one form or another
on the &lt;a class="reference external" href="https://wiki.archlinux.org/"&gt;archlinux wiki&lt;/a&gt;&lt;/p&gt;
&lt;div class="section" id="hard-drive-preparation"&gt;
&lt;h2&gt;Hard Drive Preparation&lt;/h2&gt;
&lt;p&gt;I partitioned the hard drive using windows tools.&lt;/p&gt;
&lt;!-- TODO add the instructions for windows --&gt;
&lt;p&gt;I then downloaded archlinux iso file in another machine that had
archlinux, and attached a flash drive. To setup the iso file, I
did this from the terminal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;dd&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;archlinux.iso&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sdb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4M&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;progress
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then connected this flash drive to the Asus laptop and did a
reboot. When the Asus logo shows, I pressed &amp;lt;Esc&amp;gt; so that I could
choose which bootable media to use. I selected the flash drive and
unfortunately got the error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Invalid&lt;span class="w"&gt; &lt;/span&gt;signature&lt;span class="w"&gt; &lt;/span&gt;detected.&lt;span class="w"&gt; &lt;/span&gt;Check&lt;span class="w"&gt; &lt;/span&gt;secure&lt;span class="w"&gt; &lt;/span&gt;boot&lt;span class="w"&gt; &lt;/span&gt;policy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;setup.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then went to set up and disabled secure boot policy.&lt;/p&gt;
&lt;!-- TODO add the steps for this --&gt;
&lt;p&gt;I successfully managed to enter the archlinux environment. I
verified uefi mode by using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ls&lt;span class="w"&gt; &lt;/span&gt;/sys/firmware/efi/efivars
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This gave me some content, thus it was fine.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="internet-connection"&gt;
&lt;h2&gt;Internet Connection&lt;/h2&gt;
&lt;p&gt;I connected to the internet via wifi. To do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;iw&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#to get name of wireless interface. I got wlp2s0&lt;/span&gt;
ip&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;wlp2s0&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#I had to activate the kernel interface&lt;/span&gt;
ip&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;wlp2s0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#To check if activated. There was an UP between the &amp;lt;&amp;gt; info&lt;/span&gt;
iw&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;wlp2s0&lt;span class="w"&gt; &lt;/span&gt;scan&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;less&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#list wifi Access Points in area&lt;/span&gt;
wpa_supplicant&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;wlp2s0&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;wpa_passphrase&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SSID&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;keytoaccesswifi&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-B&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#connect to wifi&lt;/span&gt;
iw&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;wlp2s0&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#to check if associated&lt;/span&gt;
dhcpd&lt;span class="w"&gt; &lt;/span&gt;wlp2s0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#to get up address from wifi&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="section" id="system-clock"&gt;
&lt;h3&gt;System Clock&lt;/h3&gt;
&lt;p&gt;To update the system clock, I did:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;timedatectl&lt;span class="w"&gt; &lt;/span&gt;set-ntp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
timedatectl&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# checks the time&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="initial-setup"&gt;
&lt;h2&gt;Initial Setup&lt;/h2&gt;
&lt;p&gt;To install arch, I had to view the partitions and the sizes so
that I could choose the correct one.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;fdisk&lt;span class="w"&gt; &lt;/span&gt;-l
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After getting the correct one:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkfs.ext4&lt;span class="w"&gt; &lt;/span&gt;/dev/sda4&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#format partition as ext4&lt;/span&gt;
mount&lt;span class="w"&gt; &lt;/span&gt;/dev/sda4&lt;span class="w"&gt; &lt;/span&gt;/mnt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#mount partition to start working with it&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then set up some basic packages for arch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pacstrap&lt;span class="w"&gt; &lt;/span&gt;/mnt&lt;span class="w"&gt; &lt;/span&gt;base&lt;span class="w"&gt; &lt;/span&gt;base-devel
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I generated the fstab:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;genfstab&lt;span class="w"&gt; &lt;/span&gt;-U&lt;span class="w"&gt; &lt;/span&gt;/mnt&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/mnt/etc/fstab
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now change into the new file system root:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;arch-chroot&lt;span class="w"&gt; &lt;/span&gt;/mnt
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I set the time zone for my system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ln&lt;span class="w"&gt; &lt;/span&gt;-sf&lt;span class="w"&gt; &lt;/span&gt;/usr/share/zoneinfo/Africa/Nairobi&lt;span class="w"&gt; &lt;/span&gt;/etc/localtime
hwclock&lt;span class="w"&gt; &lt;/span&gt;--systohc
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For the time zone once '/user/share/zoneinfo' has been type,
clicking tab will autocomplete.&lt;/p&gt;
&lt;p&gt;I set the locale by uncommenting the 'en_US.UTF-8 UTF-8' and the
'en_GB.UTF-8 UTF-8' lines in the /etc/locale.gen file and then
ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;locale-gen
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To set the default locale, I create a file /etc/locale.conf and
added LANG=en_US.UTF-8 to it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/locale.conf
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Hostnames file /etc/hosts was already existing so I did not
edit it.
I then set the root password by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;passwd
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="section" id="bootloader-installation"&gt;
&lt;h3&gt;Bootloader installation&lt;/h3&gt;
&lt;p&gt;I first installed grub and efibootmgr.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;grub&lt;span class="w"&gt; &lt;/span&gt;efibootmgr
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I needed parted so that I could know my ESP partition ( EFI system
partition).  The actual partition will have the name shown. So to
do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;parted
parted&lt;span class="w"&gt; &lt;/span&gt;/dev/sda&lt;span class="w"&gt; &lt;/span&gt;print&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# to know which was my ESP partition&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After getting the ESP partition, I mount /boot/efi onto it and
install grub.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;/dev/sda1&lt;span class="w"&gt; &lt;/span&gt;/boot/efi
grub-install&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-efi&lt;span class="w"&gt; &lt;/span&gt;--efi-directory&lt;span class="o"&gt;=&lt;/span&gt;/boot/efi&lt;span class="w"&gt; &lt;/span&gt;--bootloader-id&lt;span class="o"&gt;=&lt;/span&gt;grub
pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;intel-ucode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#enabling microcode updates&lt;/span&gt;
grub-mkconfig&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;/boot/grub/grub.cfg
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then reboot the machine. I get an error at the login prompt but
it can be ignored.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="user-creation"&gt;
&lt;h2&gt;User Creation&lt;/h2&gt;
&lt;p&gt;To create a user:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;useradd&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;-G&lt;span class="w"&gt; &lt;/span&gt;wheel&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/bin/bash&lt;span class="w"&gt; &lt;/span&gt;username
passwd&lt;span class="w"&gt; &lt;/span&gt;username
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then set up sudo on the laptop:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;sudo
&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vi&lt;span class="w"&gt; &lt;/span&gt;visudo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#and uncommnet the line %WHEEL  ALL= (ALL) ALL&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The line containing &amp;quot;%WHEEL ALL= (ALL) ALL&amp;quot; is uncommented.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="window-managers-and-other-applications"&gt;
&lt;h2&gt;Window Managers and Other Applications&lt;/h2&gt;
&lt;p&gt;I first set up xdg-dirs, and the run xdg-user-dirs-update.
I then open the file .config/user-dirs.dirs and set the values to
how I want my home directory to be organised.&lt;/p&gt;
&lt;p&gt;I then copy the /etc/xdg/user-dirs.code file to the .config folder
and set enabled to false.&lt;/p&gt;
&lt;p&gt;I then create all my directories as pwer user-dirs.dirs manually using mkdir.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;xdg-user-dirs
run&lt;span class="w"&gt; &lt;/span&gt;xdg-user-dirs-update
vi&lt;span class="w"&gt; &lt;/span&gt;.config/user-dirs.dirs
cp&lt;span class="w"&gt; &lt;/span&gt;/etc/xdg/user-dirs.conf&lt;span class="w"&gt; &lt;/span&gt;~/.config/
vi&lt;span class="w"&gt; &lt;/span&gt;.config/user-dirs.conf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#change enabled=False&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then install vim and tmux and configure it as per the &lt;a class="reference external" href="https://github.com/jnduli/dotfiles"&gt;link&lt;/a&gt; .&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;gvim&lt;span class="w"&gt; &lt;/span&gt;tmux
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I also set up powerline fonts as found &lt;a class="reference external" href="https://github.com/powerline/fonts"&gt;here&lt;/a&gt; to help in vim_airline setup.&lt;/p&gt;
&lt;p&gt;I then install zsh:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;zsh&lt;span class="w"&gt; &lt;/span&gt;zsh-completions
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then setup oh-my-zsh as per the instructions &lt;a class="reference external" href="https://github.com/robbyrussell/oh-my-zsh"&gt;here: zshlink&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I then install xorg group, sfce4 and xfce4-goodies for one of my
desktop environments.&lt;/p&gt;
&lt;p&gt;I also install i3 as my main window manager.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="other-installs"&gt;
&lt;h2&gt;Other Installs&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;python2&lt;span class="w"&gt; &lt;/span&gt;python-pip&lt;span class="w"&gt; &lt;/span&gt;python2-pip
sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;kicad&lt;span class="w"&gt; &lt;/span&gt;kicad-library&lt;span class="w"&gt; &lt;/span&gt;kicad-library-3d
sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;openssh
sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;mtp&lt;span class="w"&gt; &lt;/span&gt;gvfs-mtp
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I also use ledger to manage my finances so I have to install it.
Ledger is only found in AUR so I first installed yaourt from
instructions found &lt;a class="reference external" href="https://archlinux.fr/yaourt-en"&gt;here :yaourt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After that I install ledger with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;yaourt&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;ledger
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The following installs are requirement for my i3 config to work
properly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;redshift&lt;span class="w"&gt; &lt;/span&gt;feh&lt;span class="w"&gt; &lt;/span&gt;scrot&lt;span class="w"&gt; &lt;/span&gt;dmenu
sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;python-gobject&lt;span class="w"&gt; &lt;/span&gt;python-xdg&lt;span class="w"&gt; &lt;/span&gt;librsvg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#required for redshift-gtk&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For xfce4, I added the following shortcuts:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;exo-open&lt;span class="w"&gt; &lt;/span&gt;--launch&lt;span class="w"&gt; &lt;/span&gt;TerminalEmulator&lt;span class="w"&gt;  &lt;/span&gt;Super+Return
xfce4-terminal&lt;span class="w"&gt; &lt;/span&gt;--drop-down&lt;span class="w"&gt; &lt;/span&gt;F12
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To switch capslock and escape, I added this to my .xinitrc:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;setxkbmap&lt;span class="w"&gt; &lt;/span&gt;-option&lt;span class="w"&gt; &lt;/span&gt;caps:swapescape
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The audio by default was muted so to fix this I did the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;alsa-utils
alsamixer
&lt;span class="c1"&gt;#went to master and unmuted by pressing m&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And with that I was comfortable enough with my archlinux setup.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>Vim Airline Setup</title><link href="https://blog.jnduli.co.ke/vim-airline-setup.html" rel="alternate"/><published>2017-06-12T08:20:00+03:00</published><updated>2017-06-12T08:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-06-12:/vim-airline-setup.html</id><summary type="html">&lt;p&gt;I was watching this video on how to use vim+tmux effectively (&lt;a class="reference external" href="https://www.youtube.com/watch?v=5r6yzFEXajQ"&gt;Video Link&lt;/a&gt;), and
this guy had some really awesome looking vim. I decided to try it
out and see if I could end up with something just that great.&lt;/p&gt;
&lt;p&gt;I did my research and found two alternatives, powerline …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I was watching this video on how to use vim+tmux effectively (&lt;a class="reference external" href="https://www.youtube.com/watch?v=5r6yzFEXajQ"&gt;Video Link&lt;/a&gt;), and
this guy had some really awesome looking vim. I decided to try it
out and see if I could end up with something just that great.&lt;/p&gt;
&lt;p&gt;I did my research and found two alternatives, powerline and
vim-airline. Powerline is pretty heavy and vim-airline states
itself to be lightweight, so I went ahead and installed
vim-airline.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;quot;Added so that vim airline can get git info&lt;/span&gt;
Plugin &lt;span class="s1"&gt;&amp;#39;tpope/vim-fugitive&amp;#39;&lt;/span&gt;
Plugin &lt;span class="s1"&gt;&amp;#39;vim-airline/vim-airline&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After this I just run :PluginInstall.&lt;/p&gt;
&lt;p&gt;However, after installation, the statusline did not look that
great. I needed to do something more. I foundout that vim-airline
needs some special fonts so that it can display some things
properly, like the &amp;gt; and &amp;lt;. To do this, I had to install powerline
fonts. I followed the instruction found &lt;a class="reference external" href="https://github.com/powerline/fonts"&gt;here: powerine fonts&lt;/a&gt; and ended up installing the powerline fonts.&lt;/p&gt;
&lt;p&gt;I then switched to a powerline font in Xfce4-terminal. I use
DejaVu Sans Mono for Powerline Book.&lt;/p&gt;
&lt;p&gt;But still this was not enough. I then had to go to my .vimrc and
add some few more sections.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;quot;To allow colors in the status line&lt;/span&gt;
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;t_Co&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;256&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot;To allow status bar to be seen even before splitting&lt;/span&gt;
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;laststatus&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="c"&gt;&amp;quot;To allow powerline symbols to be seen&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:airline_powerline_fonts&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With all this I had almost reached my goal. However, I have a
10.1&amp;quot; screen laptop, and the status bar seemed to be hiding some
details because of the little screen landscape. So I decided to
change some sections. After some digging I added this to my .vimrc&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;quot;Reduces the space occupied by section z&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;:airline_section_z &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;%3p%% %l:%c&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now I have a pretty decent status bar.&lt;/p&gt;
</content><category term="Computer"/><category term="vim"/></entry><entry><title>Git Branches</title><link href="https://blog.jnduli.co.ke/git-branches-basics.html" rel="alternate"/><published>2017-06-04T15:00:00+03:00</published><updated>2017-06-04T15:00:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-06-04:/git-branches-basics.html</id><summary type="html">&lt;p&gt;Lets say we have have a project A that works really well and
serves our purpose. Then there is this new killer feature that we
want to add to the project. Adding it directly to project A is not
a really good thing as it might break whats working.&lt;/p&gt;
&lt;p&gt;So …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Lets say we have have a project A that works really well and
serves our purpose. Then there is this new killer feature that we
want to add to the project. Adding it directly to project A is not
a really good thing as it might break whats working.&lt;/p&gt;
&lt;p&gt;So what happens. We create a branch on which we start implementing
this new feature. The branch is a copy of the code, that we can
work with safely. The branch can be experimental features or just
things we want to test to see if they are stable enough.&lt;/p&gt;
&lt;p&gt;Branches are an important feature in git ahd here are the basic
commands I use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#list all branches&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#creates branch called name&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#change branch name to name&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#deletes the branch. If changes havent been&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;#merged an error message is shown.&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-D&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#force delete branch even with unmerged conflicts&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;existing-branch&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#switch to this branch&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#create branch name and switch to it&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Sometimes you create a branch but it cannot push to the server. To
fix this, you do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;--set-upstream&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch_name&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And when you clone from a server, the git branch command will only
show the master branch. To view all the branches you do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-a
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These are the branch commands I interact with most of the time.
I'll add more over time as I get more familiar with branching.&lt;/p&gt;
</content><category term="Computer"/><category term="github"/><category term="projects"/></entry><entry><title>Adb Usage at Work</title><link href="https://blog.jnduli.co.ke/adb-usage-at-work.html" rel="alternate"/><published>2017-04-09T08:20:00+03:00</published><updated>2017-04-09T08:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-04-09:/adb-usage-at-work.html</id><summary type="html">&lt;p&gt;To use adb in archlinux, first install android-tools.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;android-tools
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then add the adb resources to the android rules files. To do
this, first do lsusb, you'll get something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;lsusb
Bus&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;001&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;004&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;ID&lt;span class="w"&gt; &lt;/span&gt;12d1:256b&lt;span class="w"&gt; &lt;/span&gt;Huawei&lt;span class="w"&gt; &lt;/span&gt;Technologies&lt;span class="w"&gt; &lt;/span&gt;Co.,&lt;span class="w"&gt; &lt;/span&gt;Ltd.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To add this to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;To use adb in archlinux, first install android-tools.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;android-tools
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then add the adb resources to the android rules files. To do
this, first do lsusb, you'll get something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;lsusb
Bus&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;001&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;004&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;ID&lt;span class="w"&gt; &lt;/span&gt;12d1:256b&lt;span class="w"&gt; &lt;/span&gt;Huawei&lt;span class="w"&gt; &lt;/span&gt;Technologies&lt;span class="w"&gt; &lt;/span&gt;Co.,&lt;span class="w"&gt; &lt;/span&gt;Ltd.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To add this to the rules, open up
/etc/udev/rules.d/51-android.rules
And add this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;SUBSYSTEM&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;usb&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;ATTR&lt;span class="o"&gt;{&lt;/span&gt;idVendor&lt;span class="o"&gt;}==&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;12d1&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0660&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;plugdev&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To list all the packages installed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;adb&lt;span class="w"&gt; &lt;/span&gt;shell&lt;span class="w"&gt; &lt;/span&gt;pm&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;packages&lt;span class="w"&gt; &lt;/span&gt;-f
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To get the main activity of a package&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;adb&lt;span class="w"&gt; &lt;/span&gt;shell&lt;span class="w"&gt; &lt;/span&gt;pm&lt;span class="w"&gt; &lt;/span&gt;dump&lt;span class="w"&gt; &lt;/span&gt;com.randompackage.android.application&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MAIN
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To launch activities&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;#launches the launcher activity&lt;/span&gt;
adb&lt;span class="w"&gt; &lt;/span&gt;shell&lt;span class="w"&gt; &lt;/span&gt;monkey&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;app.package.name&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;android.intent.category.LAUNCHER&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;adb&lt;span class="w"&gt; &lt;/span&gt;shell&lt;span class="w"&gt; &lt;/span&gt;am&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;com.package.name/com.package.name.ActivityName
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To start a specific action&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;am&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;com.example.ACTION_NAME&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;com.package.name/com.package.name.ActivityName
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To install apk&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;#if not previously installed&lt;/span&gt;
adb&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;filename.apk
&lt;span class="c1"&gt;#if it had been installed eg. when upgrading&lt;/span&gt;
adb&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;filename.apk
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"/><category term="linux"/></entry><entry><title>Why To Use Github</title><link href="https://blog.jnduli.co.ke/why-to-use-github.html" rel="alternate"/><published>2017-03-19T10:20:00+03:00</published><updated>2017-03-19T10:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-03-19:/why-to-use-github.html</id><summary type="html">&lt;p&gt;Github is a really awesome tool. It's where most open source
project live.
In my case, I use github as a means of control and tracking. I've
been doing so many projects in my free time, but however I do not
have a record or something that can show what …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Github is a really awesome tool. It's where most open source
project live.
In my case, I use github as a means of control and tracking. I've
been doing so many projects in my free time, but however I do not
have a record or something that can show what I've been doing. For
example, I made a game a couple of years ago, but somehow lost the
code. So I can't actually state that I've made a game.&lt;/p&gt;
&lt;p&gt;Github too works really well with Kicad. Kicad is an electronic
schematic capture and pcb design tool. It works well because kicad
stores all of its files in text format. Thus github is a good way
to manage my circuits.&lt;/p&gt;
&lt;p&gt;Github, I believe will also help me keep a track of where I'm
coming from and where I'm going. I've discovered recently that
using github make me use it even more.&lt;/p&gt;
</content><category term="Computer"/><category term="github"/><category term="projects"/></entry><entry><title>Postgresql Weird Error - Failed To Start</title><link href="https://blog.jnduli.co.ke/postgresql-failed-to-start-error.html" rel="alternate"/><published>2017-03-12T19:44:00+03:00</published><updated>2017-03-12T19:44:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-03-12:/postgresql-failed-to-start-error.html</id><summary type="html">&lt;p&gt;After updating my Archlinux, I tried starting up postgreSQL with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systmctl&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;postgresql.service
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The service was unable to start. I then checked on what
systemctl was saying the error was.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;rookie@ArchRookie&lt;span class="w"&gt; &lt;/span&gt;eventmanagement&lt;span class="o"&gt;]&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;postgresql
&lt;span class="o"&gt;[&lt;/span&gt;sudo&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;password&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rookie:
●&lt;span class="w"&gt; &lt;/span&gt;postgresql.service&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;PostgreSQL&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;server
Loaded …&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;After updating my Archlinux, I tried starting up postgreSQL with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systmctl&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;postgresql.service
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The service was unable to start. I then checked on what
systemctl was saying the error was.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;rookie@ArchRookie&lt;span class="w"&gt; &lt;/span&gt;eventmanagement&lt;span class="o"&gt;]&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;postgresql
&lt;span class="o"&gt;[&lt;/span&gt;sudo&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;password&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rookie:
●&lt;span class="w"&gt; &lt;/span&gt;postgresql.service&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;PostgreSQL&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;server
Loaded:&lt;span class="w"&gt; &lt;/span&gt;loaded&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;/usr/lib/systemd/system/postgresql.service&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;disabled&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;vendor&lt;span class="w"&gt; &lt;/span&gt;preset:&lt;span class="w"&gt; &lt;/span&gt;disabled&lt;span class="o"&gt;)&lt;/span&gt;
Active:&lt;span class="w"&gt; &lt;/span&gt;failed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Result:&lt;span class="w"&gt; &lt;/span&gt;exit-code&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;since&lt;span class="w"&gt; &lt;/span&gt;Sun&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2017&lt;/span&gt;-02-19&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;EAT&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;3min&lt;span class="w"&gt; &lt;/span&gt;24s&lt;span class="w"&gt; &lt;/span&gt;ago
Process:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4210&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ExecStartPre&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/postgresql-check-db-dir&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PGROOT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;/data&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exited,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;/FAILURE&lt;span class="o"&gt;)&lt;/span&gt;
Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;ArchRookie&lt;span class="w"&gt; &lt;/span&gt;systemd&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Starting&lt;span class="w"&gt; &lt;/span&gt;PostgreSQL&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;server...
Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;ArchRookie&lt;span class="w"&gt; &lt;/span&gt;systemd&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;postgresql.service:&lt;span class="w"&gt; &lt;/span&gt;Control&lt;span class="w"&gt; &lt;/span&gt;process&lt;span class="w"&gt; &lt;/span&gt;exited,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exited&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;ArchRookie&lt;span class="w"&gt; &lt;/span&gt;systemd&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Failed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;PostgreSQL&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;server.
Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;ArchRookie&lt;span class="w"&gt; &lt;/span&gt;systemd&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;postgresql.service:&lt;span class="w"&gt; &lt;/span&gt;Unit&lt;span class="w"&gt; &lt;/span&gt;entered&lt;span class="w"&gt; &lt;/span&gt;failed&lt;span class="w"&gt; &lt;/span&gt;state.
Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;ArchRookie&lt;span class="w"&gt; &lt;/span&gt;systemd&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;postgresql.service:&lt;span class="w"&gt; &lt;/span&gt;Failed&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;result&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;exit-code&amp;#39;&lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then decided to check via journalctl.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;rookie@ArchRookie&lt;span class="w"&gt; &lt;/span&gt;eventmanagement&lt;span class="o"&gt;]&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;journalctl&lt;span class="w"&gt; &lt;/span&gt;-xe
--&lt;span class="w"&gt; &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;result&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;failed.
Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;ArchRookie&lt;span class="w"&gt; &lt;/span&gt;polkitd&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;321&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Unregistered
Authentication&lt;span class="w"&gt; &lt;/span&gt;Agent&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;unix-process:4201:1104590&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;system
Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;ArchRookie&lt;span class="w"&gt; &lt;/span&gt;systemd&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;postgresql.service:&lt;span class="w"&gt; &lt;/span&gt;Unit
entered&lt;span class="w"&gt; &lt;/span&gt;failed&lt;span class="w"&gt; &lt;/span&gt;state.
Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:43:52&lt;span class="w"&gt; &lt;/span&gt;ArchRookie&lt;span class="w"&gt; &lt;/span&gt;systemd&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;postgresql.service:&lt;span class="w"&gt; &lt;/span&gt;Failed
with&lt;span class="w"&gt; &lt;/span&gt;result&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;exit-code&amp;#39;&lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This too was not descriptive enough. I then went to the archlinux
wiki docs and found a solution. Apparently something had messed
up my '/var/lib/postgres/data' and so this was my fix:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;su&lt;span class="w"&gt; &lt;/span&gt;root
su&lt;span class="w"&gt; &lt;/span&gt;postgres
initdb&lt;span class="w"&gt; &lt;/span&gt;--locale&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$LANG&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-E&lt;span class="w"&gt; &lt;/span&gt;UTF8&lt;span class="w"&gt; &lt;/span&gt;-D&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/var/lib/postgres/data&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the &lt;a class="reference external" href="https://bbs.archlinux.org/viewtopic.php?id=194040URI"&gt;Source Link&lt;/a&gt;
.. Source: &lt;a class="reference external" href="https://bbs.archlinux.org/viewtopic.php?id=194040"&gt;https://bbs.archlinux.org/viewtopic.php?id=194040&lt;/a&gt;&lt;/p&gt;
</content><category term="computer"/><category term="projects"/><category term="postgresql"/></entry><entry><title>Solarized Theme</title><link href="https://blog.jnduli.co.ke/solarized-theme.html" rel="alternate"/><published>2017-02-26T08:20:00+03:00</published><updated>2017-02-26T08:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-02-26:/solarized-theme.html</id><summary type="html">&lt;p&gt;Setting up Solarized theme well&lt;/p&gt;</summary><content type="html">&lt;p&gt;When using a tool or anything for a really long time, one has to
really like how it looks like. I use the terminal, vim and tmux a
lot. So I had to look for a theme that would be easy on my eyes. A
quick internet search revealed solarized, which I then went on to
set up. I have never looked back since then.&lt;/p&gt;
&lt;h3&gt;Xfce4 terminal setup&lt;/h3&gt;
&lt;p&gt;Go to Preferences&amp;gt;Colors&lt;/p&gt;
&lt;p&gt;Then change the terminal colors to "solarized-dark"&lt;/p&gt;
&lt;h3&gt;Vim setup&lt;/h3&gt;
&lt;p&gt;I use vundle as my plugin manager in vim. So setting up solarized
was as easy as adding the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Plugin &lt;span class="s1"&gt;&amp;#39;altercation/vim-colors-solarized&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;PluginInstall
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After these I added the following lines to my  .vimrc:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;syntax&lt;/span&gt; enable
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;dark&lt;/span&gt;
&lt;span class="k"&gt;colorscheme&lt;/span&gt; solarized
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And vim looked great.
More configuration settings can be found here:
&lt;a href="https://github.com/altercation/vim-colors-solarized"&gt;solarized-github-page&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Tmux setup&lt;/h3&gt;
&lt;p&gt;I use the tmux plugin manager (&lt;a href="https://github.com/tmux-plugins/tpm"&gt;tpm-link&lt;/a&gt;). 
So to setup solarized on tmux, it's as simple as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-g&lt;span class="w"&gt; &lt;/span&gt;@plugin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;seebi/tmux-colors-solarized&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then I run prefix + I , whicn in my case it Ctrl+b and then I
press I.&lt;/p&gt;
&lt;p&gt;This will download and install the tmux solarized theme.&lt;/p&gt;
&lt;p&gt;After this I add the following line to my tmux config:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-g&lt;span class="w"&gt; &lt;/span&gt;@colors-solarized&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dark&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For more information of tmux solarized config, check here:
&lt;a href="https://github.com/seebi/tmux-colors-solarized"&gt;tmux-solarized&lt;/a&gt;&lt;/p&gt;</content><category term="Computer"/><category term="vim"/><category term="linux"/></entry><entry><title>Know Thy Editor Well</title><link href="https://blog.jnduli.co.ke/know-thy-editor-well.html" rel="alternate"/><published>2017-02-19T08:20:00+03:00</published><updated>2017-02-19T08:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-02-19:/know-thy-editor-well.html</id><summary type="html">&lt;p&gt;Someone once told me that I should really know my editor, and know
it well. I did not take this advice into consideration but lately,
as I get better and better at using vim, I think I'm beginning to
understand the fella well. &lt;/p&gt;
&lt;p&gt;If you know your editor well enough …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Someone once told me that I should really know my editor, and know
it well. I did not take this advice into consideration but lately,
as I get better and better at using vim, I think I'm beginning to
understand the fella well. &lt;/p&gt;
&lt;p&gt;If you know your editor well enough, it becomes the single point
of reference for every task you will try to do. And the more you
know your editor, the better it works for you. Also, your
performance improves significantly as you become more comfortable
with your editor.&lt;/p&gt;
&lt;p&gt;If you become comfortable with the editor, you might end up using
it for the most importabt aspects of your life. It can end up
integrating into a lot of really cool stuff you use.&lt;/p&gt;
&lt;p&gt;Here is a list of some of the things I use vim for:
    * Managing my finances, works together with ledger
    * Writing a diary/journal of my life
    * Note taking using vimwiki
    * Todo lists using vimwiki and/or vim orgmode
    * Coding -- obviously
    * Blogging
    * Server setup and management
    * Documentation
    * Make presentations&lt;/p&gt;
&lt;p&gt;As can be seen, knowing vim well will greatly optimize my time and
also effectively manage my life well. It should not only be vim,
but know that whatever editor you choose to use, know it well,
know its community and learn every day how to optimize your work.&lt;/p&gt;</content><category term="Computer"/><category term="vim"/></entry><entry><title>Changing Menu Icon MinCss</title><link href="https://blog.jnduli.co.ke/changing-menu-icon-mincss.html" rel="alternate"/><published>2017-02-12T08:55:00+03:00</published><updated>2017-02-12T08:55:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-02-12:/changing-menu-icon-mincss.html</id><summary type="html">&lt;p&gt;I wanted to make this pelican theme that is really light weight. I
did some research and came upon mincss. Now this is a really small
CSS framework that supports a wide range of browsers. For more
info, check out &lt;a href="https://github.com/owenversteeg/min/tree/gh-pages/compiled"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I encountered a small problem however. I wanted to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I wanted to make this pelican theme that is really light weight. I
did some research and came upon mincss. Now this is a really small
CSS framework that supports a wide range of browsers. For more
info, check out &lt;a href="https://github.com/owenversteeg/min/tree/gh-pages/compiled"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I encountered a small problem however. I wanted to change my menu
background colour. By default, micsss menu has a black backgroun
and a menu icon that is white in colour.&lt;/p&gt;
&lt;p&gt;So I thought they used an icon or image, only to find out mincss
has this really neat treat of using borders. The following line
shows its implementation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;nav&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;double&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;solid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code creates three lines with the border command thus the
menu icon.&lt;/p&gt;
&lt;p&gt;To make it appear well in my theme, ie. in a white background with
black lines, I just changed the code to this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;nav&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;!--everything&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;remains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;same--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I then added a bit of snippets on my own to make the background
white.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And thus I had a menu I pretty much liked.&lt;/p&gt;</content><category term="Computer"/><category term="projects"/></entry><entry><title>Tmux Usage</title><link href="https://blog.jnduli.co.ke/tmux-usage.html" rel="alternate"/><published>2017-02-05T08:20:00+03:00</published><updated>2017-02-05T08:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-02-05:/tmux-usage.html</id><summary type="html">&lt;p&gt;How I use tmux to help me out with xfce4-terminal&lt;/p&gt;</summary><content type="html">&lt;p&gt;I use xfce4-terminal which is really awesome. It light on my
computer and yet heavy on features. It has tabs, a drop down
terminal option, and many more.&lt;/p&gt;
&lt;p&gt;However, I soon came to realize I needed something more. Something
that I could use with together with the features of
xfce4-terminal. That's when I got to find tmux.&lt;/p&gt;
&lt;p&gt;Tmux put simple is a terminal multiplexer, meaning it gives you
multiple terminals within the same window i.e kinda like tabs but
more powerful. You can have multiple windows on the same screen(it
works like vsplit and hsplit of vim) and multiple windows in the
same session.&lt;/p&gt;
&lt;p&gt;To make you understand, I just have to show you how to use it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pacman&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;tmux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To start a tmux session:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tmux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After than you can create mutliple windows on screen or in buffers&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;C-b&lt;span class="w"&gt; &lt;/span&gt;c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; creates a new buffer&lt;/span&gt;
&lt;span class="s2"&gt;C-b , &amp;#39; renames a new buffer&lt;/span&gt;
&lt;span class="s2"&gt;C-b number &amp;quot;&lt;/span&gt;moves&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;numbered&lt;span class="w"&gt; &lt;/span&gt;buffer
C-b&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;#39;Creates a vsplit&lt;/span&gt;
&lt;span class="s2"&gt;C-b % &amp;quot;&lt;/span&gt;creates&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;hsplit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To move through sections I wanted to use vim directional buttons
h,j,k,l so I had to configure this in tmux config file. So I
created a .tmux.conf in my home folder and added the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;k&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;-pane&lt;span class="w"&gt; &lt;/span&gt;-U&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;j&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;-pane&lt;span class="w"&gt; &lt;/span&gt;-D&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;h&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;-pane&lt;span class="w"&gt; &lt;/span&gt;-L&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;l&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;-pane&lt;span class="w"&gt; &lt;/span&gt;-R
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So if I have multiplw window splits on screen, I just do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;C-b&lt;span class="w"&gt; &lt;/span&gt;h/j/k/l&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; move to window&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I also set the resizing of split to use &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;C-k&lt;span class="w"&gt; &lt;/span&gt;resize-pane&lt;span class="w"&gt; &lt;/span&gt;-U
&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;C-j&lt;span class="w"&gt; &lt;/span&gt;resize-pane&lt;span class="w"&gt; &lt;/span&gt;-D
&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;C-h&lt;span class="w"&gt; &lt;/span&gt;resize-pane&lt;span class="w"&gt; &lt;/span&gt;-L
&lt;span class="nb"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;C-l&lt;span class="w"&gt; &lt;/span&gt;resize-pane&lt;span class="w"&gt; &lt;/span&gt;-R
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So to resize a window split I just do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;C-b&lt;span class="w"&gt; &lt;/span&gt;C-h/j/k/l
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you have multiple windows and have exited from one, the
numbering is usually flawed ie. it can be 1,2,4,5. To renumber the
windows, I do&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;C-n&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;command mode&lt;/span&gt;
&lt;span class="s2"&gt;movew -r &amp;quot;&lt;/span&gt;renumber&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;windows
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Computer"/><category term="linux"/></entry><entry><title>Digital Ocean Server Setup</title><link href="https://blog.jnduli.co.ke/digital-ocean-server-setup.html" rel="alternate"/><published>2017-01-22T07:20:00+03:00</published><updated>2017-01-22T07:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-01-22:/digital-ocean-server-setup.html</id><summary type="html">&lt;p&gt;step by step guide on how I setup digital ocean droplet&lt;/p&gt;</summary><content type="html">&lt;p&gt;Setting up a digital ocean server is pretty straight forward.
First you have to pay some amount via paypal or credit card ( I
paid $5). Then there is an easy html page set up tool that helps set up the
account. In my case, I did not choose to use ipv6 or to use ssh
key on login. However most of the options can be changed later on
as I learnt. I chose Ubuntu 16.04 as my preffered OS of choice.
Everything wasthen setup automatically and I just had to connect
to my server.&lt;/p&gt;
&lt;p&gt;The first thing I did was add public key authentification for my
root user. I did that by:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;ssh root@server-ip&lt;/span&gt;
&lt;span class="go"&gt;answer yes to question that appears&lt;/span&gt;
&lt;span class="go"&gt;input password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This just confirms that I can log into the system. I then exit ssh
and do the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;ssh-keygen&lt;/span&gt;
&lt;span class="go"&gt;ssh-copy-id root@server-ip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After this process I can now login to my server without the need
for my password.&lt;/p&gt;
&lt;p&gt;I then add another user to the system who will have root
privileges:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;ssh root@server-ip&lt;/span&gt;
&lt;span class="go"&gt;adduser username&lt;/span&gt;
&lt;span class="go"&gt;usermod -aG sudo username&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add public key authentification:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;ssh-keygen&lt;/span&gt;
&lt;span class="go"&gt;ssh-copy-id username@server_ip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I then diabled password access via ssh. This makes it more secure
as it prevents people guessing my server password.ie. You either
have the key to access my server or not.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;sudo vi /etc/ssh/sshd_config&lt;/span&gt;
&lt;span class="go"&gt;set&lt;/span&gt;
&lt;span class="go"&gt;    PasswordAuthentification no&lt;/span&gt;
&lt;span class="go"&gt;sudo system reload sshd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;set up firewall:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;sudo ufw app list &lt;/span&gt;
&lt;span class="go"&gt;sudo ufw allow OpenSSH&lt;/span&gt;
&lt;span class="go"&gt;sudo ufw status ;should see OpenSSH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I then installed nginx as my server of choice:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt update&lt;/span&gt;
&lt;span class="go"&gt;sudo apt install nginx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then added it to my firewall:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;sudo ufw app list&lt;/span&gt;
&lt;span class="go"&gt;sudo ufw enable &amp;#39;Nginx HTTP&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;sudo ufw status&lt;/span&gt;
&lt;span class="go"&gt;systemctl status nginx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I only enable Nginx HTTP because I have not yet got an SSL
cerificate, so port 43 for HTTPS is not currently in use.&lt;/p&gt;
&lt;p&gt;This is a neat trick I got about how to get your ip address from
the terminal&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;ip addr show eth0 | grep inet | awk &amp;#39;{ print $2; }&amp;#39; | sed&lt;/span&gt;
&lt;span class="go"&gt;&amp;#39;s/\/.*$//&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt-get install curl&lt;/span&gt;
&lt;span class="go"&gt;curl -4 icanhazip.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For a database I decided to install mariadb&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt install mariadb-server mariadb-client&lt;/span&gt;
&lt;span class="go"&gt;sudo mysql_secure_installation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I then installed php:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;sudo apt-get install php-fpm php-mysql&lt;/span&gt;

&lt;span class="go"&gt;sudo vim /etc/php/7.0/fpm/php.ini&lt;/span&gt;
&lt;span class="go"&gt;set: cgi.fix_pathinfo =0; secure better the system&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Computer"/><category term="linux"/><category term="server"/></entry><entry><title>Org Mode in Vim</title><link href="https://blog.jnduli.co.ke/org-mode-in-vim.html" rel="alternate"/><published>2017-01-09T20:20:00+03:00</published><updated>2017-01-09T20:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2017-01-09:/org-mode-in-vim.html</id><summary type="html">&lt;p&gt;Emacs has org mode. It is a really great tool. This is how I use the same in vim.&lt;/p&gt;</summary><content type="html">&lt;p&gt;So emacs has this awesome tool called orgmode that I recently
saw in use. It really impressed me, especially the versatility of
it. Problem is, its emacs and I'm already a vim fan boy.&lt;/p&gt;
&lt;p&gt;So what's the next best option? Easy, look for a vim plugin, and
oh boy did I get one... vim-orgmode.&lt;/p&gt;
&lt;p&gt;It isn't perfect, heck I'd even suggest that you use the original
orgmode if you really want it. But here's how I go about using
orgmode:&lt;/p&gt;
&lt;p&gt;First install it. When using vundle( I use vundle as my plugin
manager), just place the line below in the .vimrc file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Plugin &lt;span class="s1"&gt;&amp;#39;jceb/vim-orgmode&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then here are a few commands that will make life a breeze:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;help &lt;span class="k"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;ormode &lt;span class="c"&gt;&amp;quot;tutorial doc. You should really start here.&lt;/span&gt;
/&lt;span class="nb"&gt;hh&lt;/span&gt; &lt;span class="c"&gt;&amp;quot;create a title&lt;/span&gt;
/&lt;span class="k"&gt;cn&lt;/span&gt; &lt;span class="c"&gt;&amp;quot;create a check list&lt;/span&gt;
/&lt;span class="k"&gt;sa&lt;/span&gt; &lt;span class="c"&gt;&amp;quot;create a date&lt;/span&gt;
/&lt;span class="k"&gt;cc&lt;/span&gt; &lt;span class="c"&gt;&amp;quot;mark check list as done&lt;/span&gt;
&lt;span class="k"&gt;tab&lt;/span&gt; &lt;span class="c"&gt;&amp;quot;unfold/ fold trees&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So here's how I work:
I create a daily document at ~/ that has the date of the current
day. Something like plan_sun_05_01_2016.org
Within that folder I create a tree of various plans I'd like to do
Something like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;* Plan &lt;span class="k"&gt;for&lt;/span&gt; day 
** Morning tasks [/]
** Server setup [/]
** Research [/]
** Night tasks [/]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The [/] is just a way to keep a track of the subtasks on the major
tasks. 
I then write out the subtasks. This is accomplished by \cn just
below the subtask. The [/] will also be autofilled by vim.
I can end up with a document that looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;* Task &lt;span class="k"&gt;for&lt;/span&gt; the day
** Morning Tasks [&lt;span class="m"&gt;2&lt;/span&gt;/&lt;span class="m"&gt;3&lt;/span&gt;]
   &lt;span class="p"&gt;-&lt;/span&gt; [X] Exercise
   &lt;span class="p"&gt;-&lt;/span&gt; [X] Eat breakfast
   &lt;span class="p"&gt;-&lt;/span&gt; [ ] Read emails
** Server setup [&lt;span class="m"&gt;0&lt;/span&gt;/&lt;span class="m"&gt;3&lt;/span&gt;]
   &lt;span class="p"&gt;-&lt;/span&gt; [ ] Buy account
   &lt;span class="p"&gt;-&lt;/span&gt; [ ] Set &lt;span class="k"&gt;up&lt;/span&gt; apache
   &lt;span class="p"&gt;-&lt;/span&gt; [ ] Set &lt;span class="k"&gt;up&lt;/span&gt; mysql
** Research [&lt;span class="m"&gt;0&lt;/span&gt;/&lt;span class="m"&gt;2&lt;/span&gt;]
   &lt;span class="p"&gt;-&lt;/span&gt; [ ] How &lt;span class="k"&gt;to&lt;/span&gt; use org &lt;span class="k"&gt;mode&lt;/span&gt;
   &lt;span class="p"&gt;-&lt;/span&gt; [ ] Wrtiing &lt;span class="k"&gt;vim&lt;/span&gt; scripts
** Night tasks [&lt;span class="m"&gt;0&lt;/span&gt;/&lt;span class="m"&gt;2&lt;/span&gt;]
   &lt;span class="p"&gt;-&lt;/span&gt; [ ] Read book
   &lt;span class="p"&gt;-&lt;/span&gt; [ ] Write blog post
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are a couple of things happening above here.&lt;/p&gt;
&lt;p&gt;The [2/3] is auto generated, and each time to add an item or mark
an item with /cc it is updated.&lt;/p&gt;
&lt;p&gt;Once I got the hang of it all, I read the docs a bit more. I got a
means of adding orgmodes into the global something so that I can
access their details wherever I want.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;let g:org_agenda_files = [&amp;#39;~/org/index.org&amp;#39;,&amp;#39;~/org/projects.org&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once that is set in my .vimrc, whenever I am in any org file, I
can just type "\caa" to list all items for the current week and
"\cat" to view all todos for the week. It just scans through the
files in the list shown above.&lt;/p&gt;</content><category term="Computer"/><category term="vim"/></entry><entry><title>Airtel Money and Paypal</title><link href="https://blog.jnduli.co.ke/airtel-money-and-paypal.html" rel="alternate"/><published>2016-12-20T20:50:00+03:00</published><updated>2016-12-20T20:50:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2016-12-20:/airtel-money-and-paypal.html</id><summary type="html">&lt;p&gt;Registering on Paypal with Airtel Money Card&lt;/p&gt;</summary><content type="html">&lt;p&gt;Note: This article is outdated. I haven't used these steps in a few years.&lt;/p&gt;
&lt;p&gt;Paypal is an online means of paying for goods and services. It is
especially useful when working with sites like ebay, where some
sellers flat out only want payments through paypal.&lt;/p&gt;
&lt;p&gt;Airtel Money is a competitor to Safaricom's Mpesa. What makes me
use it is that they have the Airtel Money card, which is really
easy to get and use. They are also cheaper than Mpesa. Anyway,
more on that later.&lt;/p&gt;
&lt;p&gt;So I decided I wanted to use my airtel money card with paypal. I
then registered on the Paypal site. Paypal then make a withdrawal
from my account. The purpose of this transaction is so as to
confirm that I am the owner of the card, that is, the money
transacted is not lost.&lt;/p&gt;
&lt;p&gt;So the transaction has a description with a unique 4 digit code.
The only way to access that number is from a bank statement for
the card. &lt;/p&gt;
&lt;p&gt;Unfortunately airtel money cannot provide that information. They
were rather unhelpful here and I had to physically visit their
stores before they gave me that information.  So you
have to visit Chase Bank( in Kenya). Remember to carry your
National Id and the Airtel Money card. They will print for you the
bank statement at no charge and give it to you.&lt;/p&gt;
&lt;p&gt;Once you have the statement, get the unique transaction number,
complete your registration on Paypal, and wallah! You can now use
your card through paypal.&lt;/p&gt;</content><category term="Random"/><category term="money"/></entry><entry><title>Remapping Keyboard Keys(Esc and Caps)</title><link href="https://blog.jnduli.co.ke/remapping-keyboard-keys-esc-caps.html" rel="alternate"/><published>2016-12-06T20:20:00+03:00</published><updated>2016-12-06T20:20:00+03:00</updated><author><name>John Nduli</name></author><id>tag:blog.jnduli.co.ke,2016-12-06:/remapping-keyboard-keys-esc-caps.html</id><summary type="html">&lt;p&gt;Run this in terminal:xmodmap -e "clear Lock" -e "keycode 9 = Caps_Lock NoSymbol Caps_Lock" -e "keycode 66 = Escape NoSymbol Escape"&lt;/p&gt;</summary><content type="html">&lt;p&gt;I use vim as an editor, and this comes with some curse. I press "ESC" a
lot. And yet this key is located at an inconvenient location, at the top
row of my keyboard. For a key I often use, I would rather it occurs
somewhere closer to the home row.&lt;/p&gt;
&lt;p&gt;The "CapsLock" key is one that I rarely use, yet its located at
the home row. Furthermore, its use is redundant because I can
always use the "SHIFT" key to do the same work.&lt;/p&gt;
&lt;p&gt;I found a nifty trick on how to remap these keys on my keyboard
in linux. &lt;/p&gt;
&lt;p&gt;Open the terminal and type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;xmodmap&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;clear Lock&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;keycode 9 = Caps_Lock NoSymbol Caps_Lock&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;keycode 66 = Escape NoSymbol Escape&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If this does not work replace: clear Lock with remove Lock = Caps_Lock&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;xmodmap&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;remove Lock = Caps_Lock&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;keycode 9 = Caps_Lock NoSymbol Caps_Lock&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;keycode 66 = Escape NoSymbol Escape&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, this change is temporary. On system restart the keyboard
will be the old same.&lt;/p&gt;
&lt;p&gt;To make the changes permanent within the system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;xmodmap&lt;span class="w"&gt; &lt;/span&gt;-pke&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;~/.xmodmap
&lt;span class="c1"&gt;# Add this line to ~/.xinitrc&lt;/span&gt;
xmodmap&lt;span class="w"&gt; &lt;/span&gt;.xmodmap
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Another alternative is to use &lt;code&gt;setxkbmap&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# replaces caps with escape functionality&lt;/span&gt;
setxkbmap&lt;span class="w"&gt; &lt;/span&gt;-option&lt;span class="w"&gt; &lt;/span&gt;caps:escape
&lt;span class="c1"&gt;# swaps capslock and escape&lt;/span&gt;
setxkbmap&lt;span class="w"&gt; &lt;/span&gt;-option&lt;span class="w"&gt; &lt;/span&gt;caps:swapescape
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add whatever command to the &lt;code&gt;.xinitrc&lt;/code&gt; file to work.&lt;/p&gt;
&lt;p&gt;This switch is not all hymns and praises because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My laptop just became more unusable to others&lt;/li&gt;
&lt;li&gt;My muscle memory has already got this new configuration. This
 makes it difficult to work with other machines. &lt;/li&gt;
&lt;/ul&gt;</content><category term="Computer"/><category term="linux"/><category term="vim"/></entry></feed>