<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Nduli's World - computer</title><link href="https://jnduli.co.ke/" rel="alternate"></link><link href="https://jnduli.co.ke/feeds/computer.atom.xml" rel="self"></link><id>https://jnduli.co.ke/</id><updated>2024-07-22T00:00:00+03:00</updated><entry><title>GUIX OS with GeneNetwork</title><link href="https://jnduli.co.ke/guix-os-with-genenetwork.html" rel="alternate"></link><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: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;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="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 drive_from_ls/etc/config.scm &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="nv"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;drive_from_ls &lt;span class="c1"&gt;# e.g. set root=(hd0,1)&lt;/span&gt;
cat /boot/grub/grub.cfg
&lt;span class="c1"&gt;# run the commands in the menuentry manually&lt;/span&gt;
linux /gnu/store/......
initrd /gnu/store/.....
&lt;span class="c1"&gt;# boot the OS&lt;/span&gt;
boot
&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;span class="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;Ref&lt;/span&gt;&lt;span class="p"&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootloader&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;(&amp;quot;/boot/efi&amp;quot;))&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="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;/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;span class="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootloader&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;(&amp;quot;/boot/efi&amp;quot;))&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&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;/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;span class="p"&gt;;;&lt;/span&gt; &lt;span class="nl"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&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="n"&gt;added&lt;/span&gt; &lt;span class="nf"&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="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="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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;group&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="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="s"&gt;&amp;quot;/home/rookie&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;added&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shell&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="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;$zsh&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/bin/zsh))&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="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="s"&gt;&amp;quot;netdev&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;audio&amp;quot;&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="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;/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;span class="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;non&lt;/span&gt; &lt;span class="k"&gt;free&lt;/span&gt; &lt;span class="n"&gt;linux&lt;/span&gt; &lt;span class="n"&gt;module&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;modules&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nongnu&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt; &lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nongnu&lt;/span&gt; &lt;span class="k"&gt;system&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;initrd&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operating&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;system&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firmware&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&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;firmware&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&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;span class="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;what&lt;/span&gt; &lt;span class="n"&gt;ended&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&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="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;To&lt;/span&gt; &lt;span class="n"&gt;configure&lt;/span&gt; &lt;span class="n"&gt;OpenSSH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;an&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="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="n"&gt;to&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="n"&gt;below&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
                 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&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="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="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="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="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;This&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="n"&gt;we&lt;/span&gt;
           &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;appending&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
           &lt;span class="p"&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="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="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="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="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inherit&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&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="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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&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="s"&gt;&amp;quot;non-guix.pub&amp;quot;&lt;/span&gt;
                                                &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//substitutes.nonguix.org/signing-key.pub&lt;/span&gt;
                                                &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;line&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="p"&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="p"&gt;)&lt;/span&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 update&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;span class="c1"&gt;# pick the channels file from &lt;/span&gt;
curl https://ci.genenetwork.org/channels.scm &amp;gt; channels.scm
&lt;span class="c1"&gt;# gn2 setup&lt;/span&gt;
guix pull -C channels.scm -p ~/.guix-extra-channels/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="nv"&gt;$GUIX_PROFILE&lt;/span&gt;/etc/profile
guix install genenetwork2 -p ~/.guix-extra-channels/gn2
guix install genenetwork3 -p ~/.guix-extra-channels/gn2 &lt;span class="c1"&gt;# setups an older version&lt;/span&gt;

&lt;span class="c1"&gt;# gn3 setup&lt;/span&gt;
guix pull -C channels.scm -p ~/.guix-extra-channels/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="nv"&gt;$GUIX_PROFILE&lt;/span&gt;/etc/profile
guix install genenetwork3 -p ~/.guix-extra-channels/gn3
guix install genenetwork2 -p ~/.guix-extra-channels/gn3
guix package -i python-mysqlclient -p ~/.guix-extra-channels/gn3
guix package -i python-pyld -p ~/.guix-extra-channels/gn3
pytest -k unit_tests &lt;span class="c1"&gt;# succeeds after this&lt;/span&gt;
pytest &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="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; flask run --port&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;8080&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;
&lt;/pre&gt;&lt;/div&gt;</content><category term="computer"></category></entry><entry><title>Generate HTML when Using Markdown in Vimwiki</title><link href="https://jnduli.co.ke/generate_html_when_using_markdown_in_vimwiki.html" rel="alternate"></link><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: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://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://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;npm install -D vitepress
npx vitepress init
&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;npx run docs:build
&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;span class="nx"&gt;sidebar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getSidebar&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;contentRoot&lt;/span&gt;&lt;span class="o"&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="nx"&gt;contentDirs&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;team&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;collapsible&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="nx"&gt;collapsed&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;/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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EXCLUDE_DIRS&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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="s1"&gt;&amp;#39;node_modules&amp;#39;&lt;/span&gt;&lt;span class="p"&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="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="nx"&gt;CONTENT_ROOT&lt;/span&gt; &lt;span class="o"&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="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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;content_root&lt;/span&gt; &lt;span class="o"&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="nx"&gt;CONTENT_ROOT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&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="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="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="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="p"&gt;=&amp;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="o"&gt;&amp;amp;&amp;amp;&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="o"&gt;&amp;amp;&amp;amp;&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="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="p"&gt;=&amp;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="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;/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;span class="nx"&gt;sidebar&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getSidebar&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;contentRoot&lt;/span&gt;&lt;span class="o"&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="nx"&gt;contentDirs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getSideBarFolders&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;collapsible&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="nx"&gt;collapsed&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;/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;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="w"&gt;&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="w"&gt;&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="w"&gt;&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;/pre&gt;&lt;/div&gt;</content><category term="Computer"></category></entry><entry><title>Migrate From Vimwiki To Markdown Syntax</title><link href="https://jnduli.co.ke/migrate_from_vimwiki_to_markdown_syntax.html" rel="alternate"></link><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: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;span class="p"&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="n"&gt;branch&lt;/span&gt; &lt;span class="o"&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="n"&gt;dependencies&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;mattn/calendar-vim …&lt;/span&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;span class="p"&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="n"&gt;branch&lt;/span&gt; &lt;span class="o"&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="n"&gt;dependencies&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;mattn/calendar-vim&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vimwiki_list&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;path&lt;/span&gt; &lt;span class="o"&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="n"&gt;path_html&lt;/span&gt;&lt;span class="o"&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="n"&gt;auto_tags&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;span class="n"&gt;auto_diary_index&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;span class="n"&gt;syntax&lt;/span&gt; &lt;span class="o"&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="n"&gt;ext&lt;/span&gt; &lt;span class="o"&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="c1"&gt;-- experimental folder for markdown conversion&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&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="n"&gt;path_html&lt;/span&gt;&lt;span class="o"&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="n"&gt;syntax&lt;/span&gt; &lt;span class="o"&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="n"&gt;ext&lt;/span&gt; &lt;span class="o"&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="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vimwiki_markdown_link_ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vimwiki_stripsym&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vimwiki_global_ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&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;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="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;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="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="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="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="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="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="w"&gt;&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="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;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="w"&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="w"&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="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="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="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;}}}&lt;/span&gt;&lt;span class="w"&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="w"&gt;&lt;/span&gt;

&lt;span class="err"&gt;{{{&lt;/span&gt;&lt;span class="w"&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="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="w"&gt;&lt;/span&gt;
&lt;span class="err"&gt;}}}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&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;╰─$ pandoc --from vimwiki --to commonmark_x trial.wiki
&lt;span class="c1"&gt;## Title {#Title}&lt;/span&gt;

- &lt;span class="o"&gt;[]{&lt;/span&gt;.done2&lt;span class="o"&gt;}&lt;/span&gt;list item i:
  - &lt;span class="o"&gt;[]{&lt;/span&gt;.done1&lt;span class="o"&gt;}&lt;/span&gt;sublist
    - &lt;span class="o"&gt;[]{&lt;/span&gt;.done4&lt;span class="o"&gt;}&lt;/span&gt;sub sub
    - &lt;span class="o"&gt;[]{&lt;/span&gt;.done0&lt;span class="o"&gt;}&lt;/span&gt;sub usb
    - &lt;span class="o"&gt;[]{&lt;/span&gt;.done0&lt;span class="o"&gt;}&lt;/span&gt;sub sub1
  - &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; task &lt;span class="m"&gt;1&lt;/span&gt;

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

&lt;span class="o"&gt;[&lt;/span&gt;link to file&lt;span class="o"&gt;](&lt;/span&gt;link to file &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; bash
  ls -lah
  find . -iname &lt;span class="s1"&gt;&amp;#39;*.wiki&amp;#39;&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

Another code block

      ls -lah
      find . -iname &lt;span class="s1"&gt;&amp;#39;*.wiki&amp;#39;&lt;/span&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;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;%% save me\nNormal line %% with ending\n{{{&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s1"&gt;&amp;#39;s/\{\{\{$/\{\{\{bash/g&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               -e &lt;span class="s1"&gt;&amp;#39;s/%%/TODO: comment/g&amp;#39;&lt;/span&gt;
TODO: comment save me
Normal line TODO: comment with ending
&lt;span class="o"&gt;{{{&lt;/span&gt;bash
&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;span class="nb"&gt;echo&lt;/span&gt; -e &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="se"&gt;\&lt;/span&gt;
  &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s1"&gt;&amp;#39;s/(\[.*\])\(([^#]*)((.*) &amp;quot;wikilink&amp;quot;)\)/\1\(\2.md\4\)/g&amp;#39;&lt;/span&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;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;- []{.done4}done\n- []{.done0} not_done&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done[0-3]\}/\[ \] /g&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
           -e &lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done4\}/\[X\] /g&amp;quot;&lt;/span&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;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;\\&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed -e &lt;span class="s2"&gt;&amp;quot;s/\\\&amp;#39;/\&amp;#39;/g&amp;quot;&lt;/span&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;  sed -r -i -e &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="se"&gt;\&lt;/span&gt;
    -e &lt;span class="s2"&gt;&amp;quot;s/\\\&amp;#39;/\&amp;#39;/g&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    -e &lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done[0-3]\}/\[ \] /g&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    -e &lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done4\}/\[X\] /g&amp;quot;&lt;/span&gt; &lt;span class="se"&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;/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;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

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

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

&lt;span class="k"&gt;for&lt;/span&gt; file &lt;span class="k"&gt;in&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="k"&gt;do&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;
  mv &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="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 -d &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; files &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;find . -name &lt;span class="s2"&gt;&amp;quot;*.wiki&amp;quot;&lt;/span&gt; -print0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; file &lt;span class="k"&gt;in&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="k"&gt;do&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;
  sed -r -e &lt;span class="s1"&gt;&amp;#39;s/\{\{\{$/\{\{\{bash/g&amp;#39;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;s/%%/TODO: comment/g&amp;#39;&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="p"&gt;|&lt;/span&gt; pandoc --from vimwiki --to commonmark_x -o &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;
  sed -r -i -e &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="se"&gt;\&lt;/span&gt;
    -e &lt;span class="s2"&gt;&amp;quot;s/\\\&amp;#39;/\&amp;#39;/g&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    -e &lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done[0-3]\}/\[ \] /g&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    -e &lt;span class="s2"&gt;&amp;quot;s/\[\]\{\.done4\}/\[X\] /g&amp;quot;&lt;/span&gt; &lt;span class="se"&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;
  rm &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;/pre&gt;&lt;/div&gt;</content><category term="Computer"></category></entry><entry><title>SC-IM Color Configuration</title><link href="https://jnduli.co.ke/sc-im-color-configuration.html" rel="alternate"></link><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: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;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;/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;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;/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;color &lt;span class="s2"&gt;&amp;quot;type=NORMAL fg=WHITE bg=BLACK&amp;quot;&lt;/span&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;color &lt;span class="s2"&gt;&amp;quot;type=INPUT fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
color &lt;span class="s2"&gt;&amp;quot;type=NORMAL fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
color &lt;span class="s2"&gt;&amp;quot;type=ERROR_MSG fg=RED bg=BLACK&amp;quot;&lt;/span&gt;
color &lt;span class="s2"&gt;&amp;quot;type=CELL_SELECTION fg=BLACK bg=WHITE&amp;quot;&lt;/span&gt;
color &lt;span class="s2"&gt;&amp;quot;type=HEADINGS fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
color &lt;span class="s2"&gt;&amp;quot;type=WELCOME fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&gt;
color &lt;span class="s2"&gt;&amp;quot;type=MODE fg=WHITE bg=DEFAULT_COLOR&amp;quot;&lt;/span&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"></category></entry><entry><title>Dev Experience For Personal Projects</title><link href="https://jnduli.co.ke/dev_experience_for_personal_projects.html" rel="alternate"></link><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: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"></category></entry><entry><title>Testing GUIX</title><link href="https://jnduli.co.ke/testing_guix.html" rel="alternate"></link><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: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 apt install nscd
sudo systemctl &lt;span class="nb"&gt;enable&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; /tmp
wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc …&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 apt install nscd
sudo systemctl &lt;span class="nb"&gt;enable&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; /tmp
wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
chmod +x guix-install.sh
sudo ./guix-install.sh

&lt;span class="c1"&gt;# update guix&lt;/span&gt;
guix 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 aux &lt;span class="p"&gt;|&lt;/span&gt; grep -i guix

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

&lt;span class="c1"&gt;# ensures guix libs and apps can do https&lt;/span&gt;
guix install 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="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 apt-install i3
guix install 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 install fontconfig
fc-cache -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 install python neovim python-pynvim 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 pull
guix package -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 package -i neovim --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"></category></entry><entry><title>Stack Static Missing Library With Guix</title><link href="https://jnduli.co.ke/stack_static_missing_library_with_guix.html" rel="alternate"></link><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: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;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;stack&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;/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;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;stack&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="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt; &lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="n"&gt;libraries&lt;/span&gt;&lt;span class="p"&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="n"&gt;cannot&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;such&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;directory&lt;/span&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;$ ldd .stack-work/install/x86_64-linux-tinfo6/48795ad824c5ab2c527b42cc08a43bf5cd587c042c536072710c2302b997bb41/9.2.5/bin/helloworld-exe
        linux-vdso.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007ffd0958e000&lt;span class="o"&gt;)&lt;/span&gt;
        libgmp.so.10 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; not found
        libc.so.6 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d530000&lt;span class="o"&gt;)&lt;/span&gt;
        libm.so.6 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libm.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d3ef000&lt;span class="o"&gt;)&lt;/span&gt;
        librt.so.1 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/librt.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d3e5000&lt;span class="o"&gt;)&lt;/span&gt;
        libdl.so.2 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libdl.so.2 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d3e0000&lt;span class="o"&gt;)&lt;/span&gt;
        libpthread.so.0 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libpthread.so.0 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d3be000&lt;span class="o"&gt;)&lt;/span&gt;
        libgcc_s.so.1 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/4zvswpr2h3b7dvqpvjcdam8vfhyjrmgl-gcc-12.2.0-lib/lib/libgcc_s.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d39d000&lt;span class="o"&gt;)&lt;/span&gt;
        /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/ld-linux-x86-64.so.2 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/ayc9r7162rphy4zjw8ch01pmyh214h82-glibc-2.33/lib/ld-linux-x86-64.so.2 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f5b9d6f4000&lt;span class="o"&gt;)&lt;/span&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;$ /usr/bin/ldd .stack-work/install/x86_64-linux-tinfo6/48795ad824c5ab2c527b42cc08a43bf5cd587c042c536072710c2302b997bb41/9.2.5/bin/helloworld-exe
        linux-vdso.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007ffc41cc0000&lt;span class="o"&gt;)&lt;/span&gt;
        libgmp.so.10 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /lib/x86_64-linux-gnu/libgmp.so.10 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f4148ad2000&lt;span class="o"&gt;)&lt;/span&gt;
        libc.so.6 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f4148910000&lt;span class="o"&gt;)&lt;/span&gt;
        libm.so.6 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libm.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f41487cf000&lt;span class="o"&gt;)&lt;/span&gt;
        librt.so.1 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/librt.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f41487c5000&lt;span class="o"&gt;)&lt;/span&gt;
        libdl.so.2 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libdl.so.2 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f41487c0000&lt;span class="o"&gt;)&lt;/span&gt;
        libpthread.so.0 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/libpthread.so.0 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f414879e000&lt;span class="o"&gt;)&lt;/span&gt;
        libgcc_s.so.1 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /gnu/store/4zvswpr2h3b7dvqpvjcdam8vfhyjrmgl-gcc-12.2.0-lib/lib/libgcc_s.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f414877d000&lt;span class="o"&gt;)&lt;/span&gt;
        /gnu/store/5h2w4qi9hk1qzzgi1w83220ydslinr4s-glibc-2.33/lib/ld-linux-x86-64.so.2 &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; /lib64/ld-linux-x86-64.so.2 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f4148b68000&lt;span class="o"&gt;)&lt;/span&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;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="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&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="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;noprofile&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;norc&lt;/span&gt;  
&lt;span class="k"&gt;export&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="n"&gt;build&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The binary worked without an errors.&lt;/p&gt;</content><category term="Computer"></category></entry><entry><title>Comic Site Migration to SQLite</title><link href="https://jnduli.co.ke/comic_site_migration_to_sqlite.html" rel="alternate"></link><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: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 manage.py migrate
python manage.py loaddata /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"></category></entry><entry><title>How To Code Review</title><link href="https://jnduli.co.ke/how_to_code_review.html" rel="alternate"></link><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: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"></category></entry><entry><title>My Firefox Configuration</title><link href="https://jnduli.co.ke/my_firefox_configuration.html" rel="alternate"></link><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: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="n"&gt;colors&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="n"&gt;colourscheme&lt;/span&gt; &lt;span class="n"&gt;shydactyl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&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="p"&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="mh"&gt;#1d1b19&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&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="kc"&gt;white&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="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="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="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#1d1b19&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;/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="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clipboardevents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;devPixelsPerPx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.25&lt;/span&gt;
&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;systemUsesDarkTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;toolkit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legacyUserProfileCustomizations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stylesheets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background_color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;000000&lt;/span&gt;
&lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foreground_color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&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"></category></entry><entry><title>Moving home directory to another partition</title><link href="https://jnduli.co.ke/moving_home_directory_to_another_partition.html" rel="alternate"></link><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: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; /home
du -sch &lt;span class="k"&gt;$(&lt;/span&gt;ls -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://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 /dev/sdc2 /mnt
cp -rp /home/* /mnt &lt;span class="c1"&gt;# cp -r --preserve=all /home/* /mnt might be better&lt;/span&gt;
mv /home /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         /home           ext4            rw,relatime     &lt;span class="m"&gt;0&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 -rf /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"></category></entry><entry><title>Kubernetes Basics</title><link href="https://jnduli.co.ke/kubernetes_basics.html" rel="alternate"></link><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: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 pacman -S minikube kubectl docker
sudo systemctl start docker
minikube config &lt;span class="nb"&gt;set&lt;/span&gt; driver docker
minikube 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="s"&gt;nginx:1.21.1&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt; index.html /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="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="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="nt"&gt;name&lt;/span&gt;&lt;span class="p"&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="nt"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;3&lt;/span&gt;
  &lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nt"&gt;matchLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;static-website-pod&lt;/span&gt;
  &lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;static-website-pod&lt;/span&gt;
    &lt;span class="c1"&gt;# pod template section&lt;/span&gt;
    &lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;static-website-container&lt;/span&gt;
        &lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;static:0.1.0&lt;/span&gt;
        &lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;containerPort&lt;/span&gt;&lt;span class="p"&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 start
&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;minikube -p minikube docker-env&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# ensure docker images are built in minikube context&lt;/span&gt;
docker build -t static:0.1.0 -f Dockerfile_static_content .
kubectl apply -f 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;╰─$ kubectl get deployment
NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
static-website-deployment   &lt;span class="m"&gt;3&lt;/span&gt;/3     &lt;span class="m"&gt;3&lt;/span&gt;            &lt;span class="m"&gt;3&lt;/span&gt;           17s
╰─$ kubectl get pods
NAME                                         READY   STATUS    RESTARTS   AGE
static-website-deployment-57bdbf7d94-7ngwt   &lt;span class="m"&gt;1&lt;/span&gt;/1     Running   &lt;span class="m"&gt;0&lt;/span&gt;          4s
static-website-deployment-57bdbf7d94-9l5cv   &lt;span class="m"&gt;1&lt;/span&gt;/1     Running   &lt;span class="m"&gt;0&lt;/span&gt;          4s
static-website-deployment-57bdbf7d94-gj59k   &lt;span class="m"&gt;1&lt;/span&gt;/1     Running   &lt;span class="m"&gt;0&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;╰─$ kubectl apply -f static_load_balancer.yml
service/static-load-balancer unchanged
╰─$ kubectl get services
NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;        AGE
kubernetes             ClusterIP      &lt;span class="m"&gt;10&lt;/span&gt;.96.0.1       &amp;lt;none&amp;gt;        &lt;span class="m"&gt;443&lt;/span&gt;/TCP        6d5h
static-load-balancer   LoadBalancer   &lt;span class="m"&gt;10&lt;/span&gt;.105.222.19   &amp;lt;pending&amp;gt;     &lt;span class="m"&gt;80&lt;/span&gt;:30133/TCP   116s
╰─$ curl &lt;span class="k"&gt;$(&lt;/span&gt;minikube ip&lt;span class="k"&gt;)&lt;/span&gt;:30133
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html &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;
    &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 addons &lt;span class="nb"&gt;enable&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;╰─$ kubectl get services
NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;        AGE
kubernetes             ClusterIP      &lt;span class="m"&gt;10&lt;/span&gt;.96.0.1       &amp;lt;none&amp;gt;        &lt;span class="m"&gt;443&lt;/span&gt;/TCP        6d6h
static-clusterip       ClusterIP      &lt;span class="m"&gt;10&lt;/span&gt;.109.227.9    &amp;lt;none&amp;gt;        &lt;span class="m"&gt;80&lt;/span&gt;/TCP         108s
static-load-balancer   LoadBalancer   &lt;span class="m"&gt;10&lt;/span&gt;.105.222.19   &amp;lt;pending&amp;gt;     &lt;span class="m"&gt;80&lt;/span&gt;:30133/TCP   81m
╰─$ kubectl get ingress
NAME             CLASS    HOSTS   ADDRESS     PORTS   AGE
static-ingress   &amp;lt;none&amp;gt;   *       localhost   &lt;span class="m"&gt;80&lt;/span&gt;      25m
╰─$ curl &lt;span class="k"&gt;$(&lt;/span&gt;minikube ip&lt;span class="k"&gt;)&lt;/span&gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html &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;
    &amp;lt;head&amp;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"></category></entry><entry><title>Sending Mail from Cron in Ubuntu 20.04 LTS</title><link href="https://jnduli.co.ke/sending_mail_from_cron_in_ubuntu_20_04_lts.html" rel="alternate"></link><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: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="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;06&lt;/span&gt;:14:02 ubuntu-docker-comic-misc-server 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;: sendmail: the server did not accept the mail
Dec  &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;06&lt;/span&gt;:14:02 ubuntu-docker-comic-misc-server 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;: sendmail: server message: &lt;span class="m"&gt;551&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;.7.1 Not authorised to send from this header address
Dec  &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;06&lt;/span&gt;:14:02 ubuntu-docker-comic-misc-server 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;: sendmail: could not send mail &lt;span class="o"&gt;(&lt;/span&gt;account default from /home/rookie/.config/msmtp/config&lt;span class="o"&gt;)&lt;/span&gt;
Dec  &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;06&lt;/span&gt;:14:02 ubuntu-docker-comic-misc-server 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="o"&gt;(&lt;/span&gt;rookie&lt;span class="o"&gt;)&lt;/span&gt; MAIL &lt;span class="o"&gt;(&lt;/span&gt;mailed &lt;span class="m"&gt;50&lt;/span&gt; bytes of output but got status 0x0045 from 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="m"&gt;02&lt;/span&gt; &lt;span class="m"&gt;06&lt;/span&gt;:15:02 &lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;smtp.fastmail.com &lt;span class="nv"&gt;tls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on &lt;span class="nv"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on &lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;replace_me@fastmail.com &lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;email@replace_me.com &lt;span class="nv"&gt;recipients&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;email@example.org &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="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="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="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:~$ apt policy msmtp
msmtp:
  Installed: &lt;span class="m"&gt;1&lt;/span&gt;.8.6-1
  Candidate: &lt;span class="m"&gt;1&lt;/span&gt;.8.6-1
  Version table:
 *** &lt;span class="m"&gt;1&lt;/span&gt;.8.6-1 &lt;span class="m"&gt;500&lt;/span&gt;
        &lt;span class="m"&gt;500&lt;/span&gt; http://mirrors.digitalocean.com/ubuntu focal/universe amd64 Packages
        &lt;span class="m"&gt;100&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:~$ apt policy cron
cron:
  Installed: &lt;span class="m"&gt;3&lt;/span&gt;.0pl1-136ubuntu1
  Candidate: &lt;span class="m"&gt;3&lt;/span&gt;.0pl1-136ubuntu1
  Version table:
 *** &lt;span class="m"&gt;3&lt;/span&gt;.0pl1-136ubuntu1 &lt;span class="m"&gt;500&lt;/span&gt;
        &lt;span class="m"&gt;500&lt;/span&gt; http://mirrors.digitalocean.com/ubuntu focal/main amd64 Packages
        &lt;span class="m"&gt;100&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"></category></entry><entry><title>TaskLite Setup</title><link href="https://jnduli.co.ke/tasklite-setup.html" rel="alternate"></link><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: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 -S stack-static &lt;span class="c1"&gt;# this provides statically linked libraries&lt;/span&gt;
git clone https://github.com/ad-si/TaskLite.git
&lt;span class="nb"&gt;cd&lt;/span&gt; TaskLite
stack install 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="n"&gt;file&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="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tasklite&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yaml&lt;/span&gt;
&lt;span class="n"&gt;dataDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;~/&lt;/span&gt;&lt;span class="n"&gt;gdrive_rclone&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&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; tl tasklite
tl &lt;span class="nb"&gt;help&lt;/span&gt; &lt;span class="c1"&gt;# show help&lt;/span&gt;
tl add &lt;span class="nb"&gt;read&lt;/span&gt; book &lt;span class="c1"&gt;# add task&lt;/span&gt;
tl add meeting due:2021-04-28T10:00 &lt;span class="c1"&gt;# add task with due date&lt;/span&gt;
tl add invest &lt;span class="k"&gt;in&lt;/span&gt; stocks +finances due:2021-04-28T10:00 &lt;span class="c1"&gt;# add task with due date and tag (finances)&lt;/span&gt;
tl due &lt;span class="m"&gt;2021&lt;/span&gt;-04-28T10:00 task_id &lt;span class="c1"&gt;# add due date to a task&lt;/span&gt;
tl recur P1D task_id &lt;span class="c1"&gt;# add recurrence period for tasklite&lt;/span&gt;
tl &lt;span class="k"&gt;do&lt;/span&gt; task_id &lt;span class="c1"&gt;# mark a task as done&lt;/span&gt;
tl delete task_id &lt;span class="c1"&gt;# delete a task&lt;/span&gt;
tl edit task_id &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 recur P1D task_id
tl repeat P1D 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="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; 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; 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; 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; 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; 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; 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"></category></entry><entry><title>Thinkpad T440 ArchLinux Setup</title><link href="https://jnduli.co.ke/thinkpad-t440-archlinux-setup.html" rel="alternate"></link><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: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://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://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 dd &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="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sda &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;progress &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 list &lt;span class="c1"&gt;# showed wlan0 as the wifi device&lt;/span&gt;
station wlan0 scan
station wlan0 get-networks &lt;span class="c1"&gt;# list SSIDs&lt;/span&gt;
station wlan0 connect 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 set-ntp &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 -l &lt;span class="c1"&gt;# lists devices&lt;/span&gt;

fdisk /dev/sda &lt;span class="c1"&gt;# enters fdisk to help modify this drive&lt;/span&gt;
g &lt;span class="c1"&gt;# convert to gpt partitioning scheme&lt;/span&gt;
n &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="c1"&gt;# 2nd partition 120GB for linux&lt;/span&gt;
n &lt;span class="c1"&gt;# 3rd partittion rest of files size, for home directory&lt;/span&gt;
w &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 /dev/sda2
mount /dev/sda2 /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 /mnt base linux linux-firmware openssh git networkmanager tmux i3 dmenu sway xfce4 feh scrot xautolock python python-pip gvim neovim python-pynvim xdg-user-dirs zsh zsh-completions pulseaudio ledger firefox libmtp gvfs-mtp man-db man-pages texinfo intel-ucode 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 /dev/sda3 &lt;span class="c1"&gt;# partition to ext4&lt;/span&gt;
mount /dev/sda3 /mnt/home &lt;span class="c1"&gt;# ensures home is on another partition&lt;/span&gt;
genfstab -U /mnt &amp;gt;&amp;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 /mnt
ln -sf /usr/share/zoneinfo/Africa/Nairobi /etc/localtime
hwclock --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="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8 &amp;gt;&amp;gt; /etc/locale.conf
&lt;span class="nb"&gt;echo&lt;/span&gt; ovonel &amp;gt;&amp;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 -m -G wheel -s /bin/bash username
passwd 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 -S sudo
&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vi visudo &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 /dev/sda
grub-mkconfig -o /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="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;pacman&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="n"&gt;tpacpi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bat&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;systemctl&lt;/span&gt; &lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="n"&gt;tpacpi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;pacman&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="n"&gt;tlp&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;systemctl&lt;/span&gt; &lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="n"&gt;tlp&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
</content><category term="Computer"></category><category term="linux"></category></entry><entry><title>Custom snippets in vim</title><link href="https://jnduli.co.ke/custom-snippets-in-vim.html" rel="alternate"></link><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: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="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="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="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><category term="programming"></category></entry><entry><title>First Haskell Parser (for Kindle Highlights)</title><link href="https://jnduli.co.ke/first_haskell_parser_for_kindle.html" rel="alternate"></link><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: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 new kindle-highlights simple
&lt;span class="nb"&gt;cd&lt;/span&gt; kindle-highlights
stack setup
stack ghci &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 Main
:r &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="ow"&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="nn"&gt;Text.Parsec&lt;/span&gt;


&lt;span class="nf"&gt;eogString&lt;/span&gt; &lt;span class="ow"&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="ow"&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="ow"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;endOfGroup&lt;/span&gt; &lt;span class="ow"&gt;=&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;eogString&lt;/span&gt;

&lt;span class="nf"&gt;kindleGroup&lt;/span&gt; &lt;span class="ow"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;kindleGroup&lt;/span&gt; &lt;span class="ow"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manyTill&lt;/span&gt; &lt;span class="n"&gt;anyChar&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;try&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="ow"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;kindleGroup&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;failed&amp;quot;&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="ow"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;st&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="ow"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;kindleGroup&lt;/span&gt;
  &lt;span class="n"&gt;next&lt;/span&gt;  &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;remainingGroups&lt;/span&gt;
  &lt;span class="n"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="kt"&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="ow"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;st&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="ow"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&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="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt; &lt;span class="ow"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;fail&amp;quot;&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 title
- Your Highlight on page &lt;span class="m"&gt;818&lt;/span&gt;-810 &lt;span class="p"&gt;|&lt;/span&gt; Added on Wednestday, &lt;span class="m"&gt;24&lt;/span&gt; October &lt;span class="m"&gt;2018&lt;/span&gt; &lt;span class="m"&gt;04&lt;/span&gt;:41:47

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

the actual highlighted &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="ow"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;highlight&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;fail&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;exampleGroup&lt;/span&gt;

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

&lt;span class="nf"&gt;location&lt;/span&gt; &lt;span class="ow"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;st&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="ow"&gt;=&lt;/span&gt; &lt;span class="n"&gt;between&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oneOf&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="n"&gt;locationGroupings&lt;/span&gt;

&lt;span class="nf"&gt;locationGroupings&lt;/span&gt; &lt;span class="ow"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;many1&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt;
    &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;many1&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt;
    &lt;span class="n"&gt;return&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="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="ow"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Parsec&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;st&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="ow"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
    &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&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="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;
    &lt;span class="n"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="nf"&gt;exampleGroup&lt;/span&gt; &lt;span class="ow"&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="o"&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="o"&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="o"&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="n"&gt;groups&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="nl"&gt;Parsec&lt;/span&gt; &lt;span class="nl"&gt;String&lt;/span&gt; &lt;span class="nl"&gt;st&lt;/span&gt; &lt;span class="err"&gt;[[&lt;/span&gt;&lt;span class="nl"&gt;String&lt;/span&gt;&lt;span class="err"&gt;]]&lt;/span&gt;
&lt;span class="nl"&gt;groups&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;do&lt;/span&gt;
  &lt;span class="nl"&gt;first&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nl"&gt;highlight&lt;/span&gt;
  &lt;span class="nl"&gt;next&lt;/span&gt;  &lt;span class="err"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nl"&gt;remainingGroups&lt;/span&gt;
  &lt;span class="nl"&gt;return&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;first&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;next&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;remainingGroups&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="n"&gt;Parsec&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="s"&gt;[[String]]&lt;/span&gt;
&lt;span class="n"&gt;remainingGroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&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="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;fail&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exampleGroup&lt;/span&gt; &lt;span class="o"&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="o"&gt;++&lt;/span&gt; &lt;span class="n"&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><category term="linux"></category><category term="project"></category></entry><entry><title>Python Timeit with Partial</title><link href="https://jnduli.co.ke/python-timeit-with-partial.html" rel="alternate"></link><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: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="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="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="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="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="nn"&gt;timeit&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;functools&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="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><category term="projects"></category></entry><entry><title>Working With A Bad Codebase</title><link href="https://jnduli.co.ke/working-with-a-bad-code-base.html" rel="alternate"></link><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: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><category term="random"></category></entry><entry><title>Vimwiki Website Deployment using Git Hooks</title><link href="https://jnduli.co.ke/vimwiki-website-deployment-using-git-hooks.html" rel="alternate"></link><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: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; g:vimwiki_list &lt;span class="o"&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="s2"&gt;&amp;quot;~/vimwiki&amp;quot;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;path_html&amp;quot;&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 -R -c &lt;span class="s1"&gt;&amp;#39;:VimwikiIndex&amp;#39;&lt;/span&gt; -c &lt;span class="s1"&gt;&amp;#39;:VimwikiAll2HTML&amp;#39;&lt;/span&gt; -c &lt;span class="s1"&gt;&amp;#39;qa!&amp;#39;&lt;/span&gt; &amp;lt; /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 -rav -e &lt;span class="s2"&gt;&amp;quot;ssh -p 1233&amp;quot;&lt;/span&gt; public_html/ 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 -R -c &lt;span class="s1"&gt;&amp;#39;:VimwikiIndex&amp;#39;&lt;/span&gt; -c &lt;span class="s1"&gt;&amp;#39;:VimwikiAll2HTML&amp;#39;&lt;/span&gt; -c &lt;span class="s1"&gt;&amp;#39;qa!&amp;#39;&lt;/span&gt; &amp;lt; /dev/tty
rsync -rav -e &lt;span class="s2"&gt;&amp;quot;ssh -p 1233&amp;quot;&lt;/span&gt; public_html/ 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><category term="projects"></category><category term="vim"></category></entry><entry><title>Huion 420 driver setup</title><link href="https://jnduli.co.ke/huion-420-driver-setup.html" rel="alternate"></link><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: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 pacman -S linux-headers
yay -S 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 modprobe -r hid-kye hid-uclogic hid-polostar 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 pacman -S 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="s2"&gt;&amp;quot;InputClass&amp;quot;&lt;/span&gt;
    Identifier &lt;span class="s2"&gt;&amp;quot;Huion on wacom&amp;quot;&lt;/span&gt;
    MatchProduct &lt;span class="s2"&gt;&amp;quot;HUION&amp;quot;&lt;/span&gt;
    MatchDevicePath &lt;span class="s2"&gt;&amp;quot;/dev/input/event*&amp;quot;&lt;/span&gt;
    Driver &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 --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="m"&gt;420&lt;/span&gt; Pad pad                       id: &lt;span class="m"&gt;21&lt;/span&gt;  type: PAD
HUION &lt;span class="m"&gt;420&lt;/span&gt; Pen stylus                    id: &lt;span class="m"&gt;22&lt;/span&gt;  type: 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><category term="linux"></category><category term="product"></category><category term="review"></category></entry><entry><title>Python Generators</title><link href="https://jnduli.co.ke/python-generators.html" rel="alternate"></link><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: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="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 …&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="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="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="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><category term="programming"></category></entry><entry><title>Ansible and SSH Port</title><link href="https://jnduli.co.ke/ansible-and-ssh-ports.html" rel="alternate"></link><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: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="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 -i &lt;span class="s1"&gt;&amp;#39;example.com:1234&amp;#39;&lt;/span&gt; -u &lt;span class="s1"&gt;&amp;#39;guest&amp;#39;&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="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;Example for port change&lt;/span&gt;
  &lt;span class="nt"&gt;set_fact&lt;/span&gt;&lt;span class="p"&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="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 playbook.yml -e &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><category term="programming"></category><category term="server"></category></entry><entry><title>Pagination: Review of Django's and Pelican's Implementation</title><link href="https://jnduli.co.ke/pagination-review-of-django-pelican-implementation.html" rel="alternate"></link><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: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="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="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="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="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="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="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><category term="programming"></category></entry><entry><title>Django's Cached Property</title><link href="https://jnduli.co.ke/django-cached-property-explanation.html" rel="alternate"></link><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: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="nc"&gt;cached_property&lt;/span&gt;&lt;span class="p"&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 …&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="nc"&gt;cached_property&lt;/span&gt;&lt;span class="p"&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="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="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="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="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="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="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><category term="programming"></category></entry><entry><title>Sway Window Manager</title><link href="https://jnduli.co.ke/sway-window-manager.html" rel="alternate"></link><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: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 -S wlroots-git 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="s2"&gt;&amp;quot;1267:12328:ELAN1300:00_04F3:3028_Touchpad&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    dwt enabled
    tap 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="nv"&gt;$mod&lt;/span&gt;+F12 &lt;span class="nb"&gt;exec&lt;/span&gt; xfce4-terminal --drop-down --title&lt;span class="o"&gt;=&lt;/span&gt;dropdown
for_window &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; floating &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="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="nb"&gt;export&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; 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 eDP-1 resolution 1920x1080 position &lt;span class="m"&gt;0&lt;/span&gt;,0
output HDMI-A-1 resolution 1280x1024 position &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><category term="window-managers"></category></entry><entry><title>Fixing Small Fonts on My Laptop</title><link href="https://jnduli.co.ke/fixing-small-fonts-on-my-laptop.html" rel="alternate"></link><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: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="m"&gt;0&lt;/span&gt;: minimum &lt;span class="m"&gt;8&lt;/span&gt; x &lt;span class="m"&gt;8&lt;/span&gt;, current &lt;span class="m"&gt;1920&lt;/span&gt; x &lt;span class="m"&gt;1080&lt;/span&gt;, maximum &lt;span class="m"&gt;32767&lt;/span&gt; x &lt;span class="m"&gt;32767&lt;/span&gt;
eDP1 connected primary 1920x1080+0+0 &lt;span class="o"&gt;(&lt;/span&gt;normal left inverted right x axis y axis&lt;span class="o"&gt;)&lt;/span&gt; 290mm x 170mm
   1920x1080     &lt;span class="m"&gt;60&lt;/span&gt;.05*+  &lt;span class="m"&gt;59&lt;/span&gt;.93
   1680x1050     &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; grep -B2 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="c1"&gt;#0:&lt;/span&gt;
  dimensions:    1920x1080 pixels &lt;span class="o"&gt;(&lt;/span&gt;508x285 millimeters&lt;span class="o"&gt;)&lt;/span&gt;
  resolution:    96x96 dots per 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="s2"&gt;&amp;quot;Monitor&amp;quot;&lt;/span&gt;
    Identifier             &lt;span class="s2"&gt;&amp;quot;eDP1&amp;quot;&lt;/span&gt;
    DisplaySize            &lt;span class="m"&gt;290&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="c1"&gt;#0:&lt;/span&gt;
  dimensions:    1920x1080 pixels &lt;span class="o"&gt;(&lt;/span&gt;290x170 millimeters&lt;span class="o"&gt;)&lt;/span&gt;
  resolution:    168x161 dots per 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><category term="linux"></category></entry><entry><title>Bluetooth Speakers Problems</title><link href="https://jnduli.co.ke/fixing-bluetooth-speaker-problems.html" rel="alternate"></link><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: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 systemctl start bluetooth.service
bluetoothctl
&lt;span class="c1"&gt;# Within the bluetoothctl environment&lt;/span&gt;
power on
agent on
default-agent
scan on
pair 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 systemctl start bluetooth.service
bluetoothctl
&lt;span class="c1"&gt;# Within the bluetoothctl environment&lt;/span&gt;
power on
agent on
default-agent
scan on
pair A4:A7:B5:22:E6:F5
connect 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 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 --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 pacman -S 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><category term="linux"></category></entry><entry><title>Freeing up Space in my Linux Machine</title><link href="https://jnduli.co.ke/freeing-up-space-in-linux-machine.html" rel="alternate"></link><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: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 -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      Size  Used Avail Use% Mounted on
dev             &lt;span class="m"&gt;3&lt;/span&gt;.9G     &lt;span class="m"&gt;0&lt;/span&gt;  &lt;span class="m"&gt;3&lt;/span&gt;.9G   &lt;span class="m"&gt;0&lt;/span&gt;% /dev
run             &lt;span class="m"&gt;3&lt;/span&gt;.9G  &lt;span class="m"&gt;1&lt;/span&gt;.4M  &lt;span class="m"&gt;3&lt;/span&gt;.9G   &lt;span class="m"&gt;1&lt;/span&gt;% /run
/dev/sda5       106G   93G  &lt;span class="m"&gt;7&lt;/span&gt;.4G  &lt;span class="m"&gt;93&lt;/span&gt;% /
tmpfs           &lt;span class="m"&gt;3&lt;/span&gt;.9G  132M  &lt;span class="m"&gt;3&lt;/span&gt;.8G   &lt;span class="m"&gt;4&lt;/span&gt;% /dev/shm
tmpfs           &lt;span class="m"&gt;3&lt;/span&gt;.9G     &lt;span class="m"&gt;0&lt;/span&gt;  &lt;span class="m"&gt;3&lt;/span&gt;.9G   &lt;span class="m"&gt;0&lt;/span&gt;% /sys/fs/cgroup
tmpfs           &lt;span class="m"&gt;3&lt;/span&gt;.9G  &lt;span class="m"&gt;8&lt;/span&gt;.0K  &lt;span class="m"&gt;3&lt;/span&gt;.9G   &lt;span class="m"&gt;1&lt;/span&gt;% /tmp
/dev/sda6        41G   20G   21G  &lt;span class="m"&gt;50&lt;/span&gt;% /run/media/silo
tmpfs           787M   20K  787M   &lt;span class="m"&gt;1&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 -sch /* &lt;span class="p"&gt;|&lt;/span&gt; sort -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     /var
14G     /opt
20G     /run
33G     /home
36G     /usr
113G    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 -sch .&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="p"&gt;|&lt;/span&gt; sort -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 -sch /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="p"&gt;|&lt;/span&gt; sort -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="n"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&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 pacman -Scc
sudo yay -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 -Qi &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;Name\|Size\|Description&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; cut -d: -f2 &lt;span class="p"&gt;|&lt;/span&gt; paste - - - &lt;span class="p"&gt;|&lt;/span&gt; awk -F&lt;span class="s1"&gt;&amp;#39;\t&amp;#39;&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="p"&gt;|&lt;/span&gt; sort -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 pacman -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 pacman -Rns &lt;span class="k"&gt;$(&lt;/span&gt;pacman -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 file
rm -r 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 -r ./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 ~/.cache/ -type f -atime +365 -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 docker system df -v
sudo docker system prune
sudo docker volume 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 docker ps -a
sudo docker rm 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 docker images -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 docker images &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="se"&gt;\&amp;lt;&lt;/span&gt;none&lt;span class="se"&gt;\&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;{print $3}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs sudo docker 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><category term="linux"></category></entry><entry><title>Document Scaning in Arch Linux</title><link href="https://jnduli.co.ke/document-scaning-in-archgit-branches-basics.html" rel="alternate"></link><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: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 pacman -S 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 pacman -S 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 pacman -S 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 -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="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; is a Hewlett-Packard HP_LaserJet_Pro_MFP_M127fw 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 --device &lt;span class="s2"&gt;&amp;quot;device name&amp;quot;&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 --device &lt;span class="s1"&gt;&amp;#39;hpaio:/net/HP_LaserJet_Pro_MFP_M127fw?ip=192.168.1.27&amp;#39;&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 options specific to device &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;:
  Scan mode:
    --mode Lineart&lt;span class="p"&gt;|&lt;/span&gt;Gray&lt;span class="p"&gt;|&lt;/span&gt;Color &lt;span class="o"&gt;[&lt;/span&gt;Lineart&lt;span class="o"&gt;]&lt;/span&gt;
        Selects the scan mode &lt;span class="o"&gt;(&lt;/span&gt;e.g., lineart, monochrome, or color&lt;span class="o"&gt;)&lt;/span&gt;.
    --resolution &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="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        Sets the resolution of the scanned image.
    --source Flatbed&lt;span class="p"&gt;|&lt;/span&gt;ADF &lt;span class="o"&gt;[&lt;/span&gt;Flatbed&lt;span class="o"&gt;]&lt;/span&gt;
        Selects the scan &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;such as a document-feeder&lt;span class="o"&gt;)&lt;/span&gt;.
  Advanced:
    --brightness -1000..1000 &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;
        Controls the brightness of the acquired image.
    --contrast -1000..1000 &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;
        Controls the contrast of the acquired image.
    --compression None&lt;span class="p"&gt;|&lt;/span&gt;JPEG &lt;span class="o"&gt;[&lt;/span&gt;JPEG&lt;span class="o"&gt;]&lt;/span&gt;
        Selects the scanner compression method &lt;span class="k"&gt;for&lt;/span&gt; faster scans, possibly at
        the expense of image quality.
    --jpeg-quality &lt;span class="m"&gt;0&lt;/span&gt;..100 &lt;span class="o"&gt;[&lt;/span&gt;inactive&lt;span class="o"&gt;]&lt;/span&gt;
        Sets the scanner JPEG compression factor. Larger numbers mean better
        compression, and smaller numbers mean better image quality.
  Geometry:
    -l &lt;span class="m"&gt;0&lt;/span&gt;..215.9mm &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;
        Top-left x position of scan area.
    -t &lt;span class="m"&gt;0&lt;/span&gt;..296.926mm &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;
        Top-left y position of scan area.
    -x &lt;span class="m"&gt;0&lt;/span&gt;..215.9mm &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;
        Width of scan-area.
    -y &lt;span class="m"&gt;0&lt;/span&gt;..296.926mm &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;
        Height of 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 --device &lt;span class="s1"&gt;&amp;#39;hpaio:/net/HP_LaserJet_Pro_MFP_M127fw?ip=192.168.1.27&amp;#39;&lt;/span&gt; --format&lt;span class="o"&gt;=&lt;/span&gt;tiff --mode&lt;span class="o"&gt;=&lt;/span&gt;color  --resolution&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;75&lt;/span&gt; &amp;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="m"&gt;1&lt;/span&gt;.tiff &lt;span class="m"&gt;2&lt;/span&gt;.tiff &lt;span class="m"&gt;3&lt;/span&gt;.tiff output.tiff
tiffpdf -j output.tiff -o 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 -p letter -j -q &lt;span class="m"&gt;75&lt;/span&gt; -t &lt;span class="s2"&gt;&amp;quot;title&amp;quot;&lt;/span&gt; -f -o title.pdf 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: Backing store not supported.
tiff2pdf: Error writing encoded strip to output PDF sm.pdf.
tiff2pdf: An error occurred creating output PDF 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="m"&gt;1&lt;/span&gt;.pdf &lt;span class="m"&gt;2&lt;/span&gt;.pdf 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><category term="linux"></category></entry><entry><title>When Memory is not enough</title><link href="https://jnduli.co.ke/when-memory-is-not-enough.html" rel="alternate"></link><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: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 fallocate -l 10G /swapfile
sudo chmod &lt;span class="m"&gt;600&lt;/span&gt; /swapfile
sudo mkswap /swapfile
swapon /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 -a
rm -f /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="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;sysctl&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;sysctl&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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 cp /etc/fstab /etc/fstab.bak &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="s1"&gt;&amp;#39;/swapfile none swap sw 0 0&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo tee -a /etc/fstab
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;vm.swappiness=10&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo tee -a /etc/sysctl.conf
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;vm.vfs_cache_pressure=50&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo tee -a /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><category term="linux"></category><category term="server"></category></entry><entry><title>Jogging Time Tracking In Google Sheets</title><link href="https://jnduli.co.ke/jogging-time-tracking=in-google-sheets.html" rel="alternate"></link><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: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="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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&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="k"&gt;return&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="o"&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="o"&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="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="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="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="k"&gt;return&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;minimum_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;index_minimum&lt;/span&gt; &lt;span class="o"&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="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&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="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="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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;minimum_time&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="nx"&gt;minimum_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;index_minimum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&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><category term="projects"></category></entry><entry><title>Testing Asynchronous Calls in VueJS</title><link href="https://jnduli.co.ke/testing-asynchronous-calls-in-vue.html" rel="alternate"></link><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: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="nx"&gt;Vue&lt;/span&gt; &lt;span class="nx"&gt;from&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="nx"&gt;Vuex&lt;/span&gt; &lt;span class="nx"&gt;from&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="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;new&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="nx"&gt;state&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;mutations&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setQuotes&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;newQuotes&lt;/span&gt;&lt;span class="p"&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="nx"&gt;quotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newQuotes&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;setRandomQuote&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="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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;randomQuote&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;getQuotes&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="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&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="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="p"&gt;=&amp;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="s1"&gt;&amp;#39;setQuotes&amp;#39;&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;getRandomQuote&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="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&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="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="p"&gt;=&amp;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="s1"&gt;&amp;#39;setRandomQuote&amp;#39;&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="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="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="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="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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="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="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="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="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="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="p"&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="p"&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="nx"&gt;div&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="nx"&gt;is&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&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="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="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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;from&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="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&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="nx"&gt;computed&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;randomQuote&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;=&amp;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="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;getQuote&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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="p"&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 install moxios --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="nx"&gt;Vue&lt;/span&gt; &lt;span class="nx"&gt;from&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="nx"&gt;Vuex&lt;/span&gt; &lt;span class="nx"&gt;from&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="p"&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;from&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="nx"&gt;RandomQuote&lt;/span&gt; &lt;span class="nx"&gt;from&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="nx"&gt;store&lt;/span&gt; &lt;span class="nx"&gt;from&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="nx"&gt;axios&lt;/span&gt; &lt;span class="nx"&gt;from&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="nx"&gt;VueAxios&lt;/span&gt; &lt;span class="nx"&gt;from&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="nx"&gt;moxios&lt;/span&gt; &lt;span class="nx"&gt;from&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="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="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;wrapper&lt;/span&gt;

  &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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="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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1622&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&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="nx"&gt;content&lt;/span&gt;&lt;span class="o"&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="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;wrapper&lt;/span&gt; &lt;span class="o"&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="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="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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="p"&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="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="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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="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="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;randomQuote&lt;/span&gt; &lt;span class="o"&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="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="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/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="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="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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="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="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;randomQuote&lt;/span&gt; &lt;span class="o"&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="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="nx"&gt;done&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;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="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;flushPromises&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;randomQuote&lt;/span&gt; &lt;span class="o"&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="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="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;flushPromises&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;flushPromises&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;randomQuote&lt;/span&gt; &lt;span class="o"&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="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><category term="projects"></category><category term="programming"></category></entry><entry><title>Jupyter Notebook Setup on a VPS</title><link href="https://jnduli.co.ke/jupyter-notebook-setup-in-vps.html" rel="alternate"></link><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: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 apt update
sudo apt 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 -m -s /bin/bash user
usermod -aG sudo username
sudo passwd username
su - 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 apt install 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 -m pip install --user numpy scipy matplotlib pandas sympy nose seaborn pillow keras tensorflow scikit-learn scikit-image kaggle-cli
pythom3 -m pip install ipython&lt;span class="o"&gt;[&lt;/span&gt;notebook&lt;span class="o"&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 apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev 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 apt-get install gcc gfortran python-dev libopenblas-dev 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 apt-get install libxml2-dev libxslt1-dev 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="o"&gt;[&lt;/span&gt; -d &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="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&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 notebook --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 notebook 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 jupyter 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 -L https://github.com/lherman-cs/tensorflow-aarch64/releases/download/r1.4/tensorflow-1.4.0rc0-cp35-cp35m-linux_aarch64.whl &amp;gt; /tmp/tensorflow-1.4.0rc0-cp35-cp35m-linux_aarch64.whl
python3 -m pip install /tmp/tensorflow-1.4.0rc0-cp35-cp35m-linux_aarch64.whl
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"></category><category term="projects"></category></entry><entry><title>SSH AND SERVERS</title><link href="https://jnduli.co.ke/ssh-and-servers.html" rel="alternate"></link><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: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 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 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 -t rsa -b &lt;span class="m"&gt;4096&lt;/span&gt; -C &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 -i file.pub 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 -i /path/to/privatekey 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 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 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 example.com
    ForwardAgent 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="k"&gt;$(&lt;/span&gt;ssh-agent&lt;span class="k"&gt;)&lt;/span&gt;
ssh-add ~/.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 -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><category term="linux"></category><category term="server"></category></entry><entry><title>SciKit-Learn GraphSearch CV</title><link href="https://jnduli.co.ke/scikit-learn-graphsearch-cv.html" rel="alternate"></link><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: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="nn"&gt;sklearn.model_selection&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="nn"&gt;sklearn&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="nn"&gt;sklearn.model_selection&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><category term="machine-learning"></category></entry><entry><title>Ansible</title><link href="https://jnduli.co.ke/ansible.html" rel="alternate"></link><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: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 --ask-become-pass 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="o"&gt;=&lt;/span&gt; ansible-playbook --ask-become-pass

&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;$(&lt;/span&gt;ANSIBLE_SUDO&lt;span class="k"&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><category term="programming"></category><category term="server"></category></entry><entry><title>Project Management in Google Sheets</title><link href="https://jnduli.co.ke/project-management-in-google-sheets.html" rel="alternate"></link><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: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="nx"&gt;createTimeDrivenTriggers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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="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="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="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="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;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&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="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="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="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="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&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;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="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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;emailCol&lt;/span&gt; &lt;span class="o"&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;emails&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;emailCol&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&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="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="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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&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="k"&gt;if&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="o"&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="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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&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="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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&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="k"&gt;return&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="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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dateDueCol&lt;/span&gt; &lt;span class="o"&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;featuresCol&lt;/span&gt; &lt;span class="o"&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;statusCol&lt;/span&gt; &lt;span class="o"&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="nx"&gt;data&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="nx"&gt;dateDueCol&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;featuresCol&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;statusCol&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt; &lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&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="nx"&gt;statusCol&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="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&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;span class="c1"&gt;// checkLateDateDues(dateDueCol, statusCol, featuresCol, data);&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="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="nx"&gt;statusCol&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="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// loop through the date due column only&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dateNow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&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="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="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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dateDue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rowRange&lt;/span&gt; &lt;span class="o"&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="mf"&gt;0&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateNow&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dateDue&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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="o"&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="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="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; was due on &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dateDue&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="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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&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="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="p"&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="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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;activeSheet&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sheetName&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="o"&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="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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;columnEditted&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rowEditted&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;valueInput&lt;/span&gt; &lt;span class="o"&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dateDueCol&lt;/span&gt; &lt;span class="o"&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;statusCol&lt;/span&gt; &lt;span class="o"&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="nx"&gt;data&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="nx"&gt;dateDueCol&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;statusCol&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;columnEditted&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;dateDueCol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rowRange&lt;/span&gt; &lt;span class="o"&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="mf"&gt;0&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="c1"&gt;// var dateInput = data[rowEditted][columnEditted];&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="nx"&gt;valueInput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;columnEditted&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;statusCol&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;valueInput&lt;/span&gt; &lt;span class="o"&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="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rowRange&lt;/span&gt; &lt;span class="o"&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="mf"&gt;0&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="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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&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="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="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;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><category term="projects"></category></entry><entry><title>ArchLinux Signature Error</title><link href="https://jnduli.co.ke/archlinux-pacman-signature-error.html" rel="alternate"></link><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: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 pacman -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: zstd: signature from &lt;span class="s2"&gt;&amp;quot;Andrzej Giniewicz (giniu) &amp;lt;randomemail@gmail.com&amp;gt;&amp;quot;&lt;/span&gt; is marginal trust
:: File /var/cache/pacman/pkg/zstd-1.3.2-1-x86_64.pkg.tar.xz is corrupted &lt;span class="o"&gt;(&lt;/span&gt;invalid or corrupted package &lt;span class="o"&gt;(&lt;/span&gt;PGP …&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 pacman -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: zstd: signature from &lt;span class="s2"&gt;&amp;quot;Andrzej Giniewicz (giniu) &amp;lt;randomemail@gmail.com&amp;gt;&amp;quot;&lt;/span&gt; is marginal trust
:: File /var/cache/pacman/pkg/zstd-1.3.2-1-x86_64.pkg.tar.xz is corrupted &lt;span class="o"&gt;(&lt;/span&gt;invalid or corrupted package &lt;span class="o"&gt;(&lt;/span&gt;PGP signature&lt;span class="o"&gt;))&lt;/span&gt;.
Do you want to delete it? &lt;span class="o"&gt;[&lt;/span&gt;Y/n&lt;span class="o"&gt;]&lt;/span&gt; Y
error: failed to commit transaction &lt;span class="o"&gt;(&lt;/span&gt;invalid or corrupted package &lt;span class="o"&gt;(&lt;/span&gt;PGP signature&lt;span class="o"&gt;))&lt;/span&gt;
Errors occurred, no packages were 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 pacman -Sy archlinux-keyring
sudo pacman-key --populate archlinux
sudo pacman-key --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><category term="linux"></category></entry><entry><title>Using Pass - A Password Manager/Generator</title><link href="https://jnduli.co.ke/password-manager-pass.html" rel="alternate"></link><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: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 pacman -S 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 init 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 insert /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: email@dns.com: skipped: No public key
gpg: &lt;span class="o"&gt;[&lt;/span&gt;stdin&lt;span class="o"&gt;]&lt;/span&gt;: encryption failed: No public key
Password encryption 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 --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 generate name/of/service &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 -n generate name/of/service &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 edit name/of/service or pass 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 name/of/service &lt;span class="c1"&gt;# displays the password&lt;/span&gt;
pass -c name/of/service &lt;span class="c1"&gt;# copies the password to xclip&lt;/span&gt;

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

pass git init &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><category term="linux"></category></entry><entry><title>Keeping a Diary in Vim</title><link href="https://jnduli.co.ke/keeping-diary-in-vim.html" rel="alternate"></link><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: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><category term="vim"></category></entry><entry><title>I3 Window Manager</title><link href="https://jnduli.co.ke/i3-window-manager.html" rel="alternate"></link><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: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 pacman -S i3wm i3lock i3status 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="nv"&gt;$mod&lt;/span&gt;+Return &lt;span class="nb"&gt;exec&lt;/span&gt; xfce4-terminal
&lt;span class="c1"&gt;# xfce4 dropdown terminal&lt;/span&gt;
bindsym F12 &lt;span class="nb"&gt;exec&lt;/span&gt; xfce4-terminal --drop-down
for_window &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; floating &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="nv"&gt;$mod&lt;/span&gt;+h focus left
bindsym &lt;span class="nv"&gt;$mod&lt;/span&gt;+j focus down
bindsym &lt;span class="nv"&gt;$mod&lt;/span&gt;+k focus up
bindsym &lt;span class="nv"&gt;$mod&lt;/span&gt;+l focus right

&lt;span class="c1"&gt;# move focused window&lt;/span&gt;
bindsym &lt;span class="nv"&gt;$mod&lt;/span&gt;+Shift+h move left
bindsym &lt;span class="nv"&gt;$mod&lt;/span&gt;+Shift+j move down
bindsym &lt;span class="nv"&gt;$mod&lt;/span&gt;+Shift+k move up
bindsym &lt;span class="nv"&gt;$mod&lt;/span&gt;+Shift+l move 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; --no-startup-id 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="nv"&gt;$mod&lt;/span&gt;+p &lt;span class="nb"&gt;exec&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; feh --bg-scale ~/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><category term="window-managers"></category></entry><entry><title>GRUB RESCUE FiX</title><link href="https://jnduli.co.ke/grub_rescue_fix.html" rel="alternate"></link><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: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 …&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="o"&gt;(&lt;/span&gt;hd0,gpt2&lt;span class="o"&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="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="o"&gt;(&lt;/span&gt;hd0,gpt2&lt;span class="o"&gt;)&lt;/span&gt;/
ls &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="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="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 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 /dev/sda1 /boot/efi
sudo grub-install --target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-efi --efi-directory&lt;span class="o"&gt;=&lt;/span&gt;/boot/efi --bootloader-id&lt;span class="o"&gt;=&lt;/span&gt;grub
sudo grub-mkconfig -o /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://jnduli.co.ke/asus-zenbook-archlinux-setup.html"&gt;here&lt;/a&gt;&lt;/p&gt;
</content><category term="Computer"></category><category term="linux"></category></entry><entry><title>Asus Zenbook Keyboard &amp; Screen Brightness Fix On i3</title><link href="https://jnduli.co.ke/asus-zenbook-keyboard-screen-issues-fix.html" rel="alternate"></link><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: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><category term="linux"></category></entry><entry><title>My First Vim Function</title><link href="https://jnduli.co.ke/my-first-vim-function.html" rel="alternate"></link><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: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="nf"&gt;TodoPercentage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;normal&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;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="n"&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><category term="vim"></category><category term="programming"></category></entry><entry><title>ASUS ZenBook UX330UA ArchLinux Setup</title><link href="https://jnduli.co.ke/asus-zenbook-archlinux-setup.html" rel="alternate"></link><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: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="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;archlinux.iso &lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sdb &lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4M &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 signature detected. Check secure boot policy &lt;span class="k"&gt;in&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 /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 dev &lt;span class="c1"&gt;#to get name of wireless interface. I got wlp2s0&lt;/span&gt;
ip link &lt;span class="nb"&gt;set&lt;/span&gt; wlp2s0 up &lt;span class="c1"&gt;#I had to activate the kernel interface&lt;/span&gt;
ip link show wlp2s0 &lt;span class="c1"&gt;#To check if activated. There was an UP between the &amp;lt;&amp;gt; info&lt;/span&gt;
iw dev wlp2s0 scan &lt;span class="p"&gt;|&lt;/span&gt; less &lt;span class="c1"&gt;#list wifi Access Points in area&lt;/span&gt;
wpa_supplicant -i wlp2s0 -c &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;wpa_passphrase &lt;span class="s2"&gt;&amp;quot;SSID&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;keytoaccesswifi&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; -B &lt;span class="c1"&gt;#connect to wifi&lt;/span&gt;
iw dev wlp2s0 link &lt;span class="c1"&gt;#to check if associated&lt;/span&gt;
dhcpd wlp2s0 &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 set-ntp &lt;span class="nb"&gt;true&lt;/span&gt;
timedatectl status &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 -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 /dev/sda4 &lt;span class="c1"&gt;#format partition as ext4&lt;/span&gt;
mount /dev/sda4 /mnt &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 /mnt base 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 -U /mnt &amp;gt;&amp;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 /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 -sf /usr/share/zoneinfo/Africa/Nairobi /etc/localtime
hwclock --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="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8 &amp;gt;&amp;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 -S grub 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 pacman -S parted
parted /dev/sda print &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 /dev/sda1 /boot/efi
grub-install --target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-efi --efi-directory&lt;span class="o"&gt;=&lt;/span&gt;/boot/efi --bootloader-id&lt;span class="o"&gt;=&lt;/span&gt;grub
pacman -S intel-ucode &lt;span class="c1"&gt;#enabling microcode updates&lt;/span&gt;
grub-mkconfig -o /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 -m -G wheel -s /bin/bash username
passwd 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 -S sudo
&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vi visudo &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 pacman -S xdg-user-dirs
run xdg-user-dirs-update
vi .config/user-dirs.dirs
cp /etc/xdg/user-dirs.conf ~/.config/
vi .config/user-dirs.conf &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 pacman -S gvim 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 pacman -S zsh 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 pacman -S python python2 python-pip python2-pip
sudo pacman -S kicad kicad-library kicad-library-3d
sudo pacman -S openssh
sudo pacman -S mtp 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 -S 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 pacman -S redshift feh scrot dmenu
sudo pacman -S python-gobject python-xdg librsvg &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 --launch TerminalEmulator  Super+Return
xfce4-terminal --drop-down 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 -option 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 pacman -S 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><category term="linux"></category></entry><entry><title>Vim Airline Setup</title><link href="https://jnduli.co.ke/vim-airline-setup.html" rel="alternate"></link><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: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><category term="vim"></category></entry><entry><title>Git Branches</title><link href="https://jnduli.co.ke/git-branches-basics.html" rel="alternate"></link><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: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 branch &lt;span class="c1"&gt;#list all branches&lt;/span&gt;
git branch &amp;lt;name&amp;gt; &lt;span class="c1"&gt;#creates branch called name&lt;/span&gt;
git branch -m &amp;lt;name&amp;gt; &lt;span class="c1"&gt;#change branch name to name&lt;/span&gt;
git branch -d &amp;lt;name&amp;gt; &lt;span class="c1"&gt;#deletes the branch. If changes havent been&lt;/span&gt;
                    &lt;span class="c1"&gt;#merged an error message is shown.&lt;/span&gt;
git branch -D &amp;lt;name&amp;gt; &lt;span class="c1"&gt;#force delete branch even with unmerged conflicts&lt;/span&gt;
git checkout &amp;lt;existing-branch&amp;gt; &lt;span class="c1"&gt;#switch to this branch&lt;/span&gt;
git checkout -b &amp;lt;name&amp;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 push --set-upstream origin &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 branch -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><category term="github"></category><category term="projects"></category></entry><entry><title>Adb Usage at Work</title><link href="https://jnduli.co.ke/adb-usage-at-work.html" rel="alternate"></link><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: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 pacman -S 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="m"&gt;001&lt;/span&gt; Device &lt;span class="m"&gt;004&lt;/span&gt;: ID 12d1:256b Huawei Technologies Co., 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 pacman -S 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="m"&gt;001&lt;/span&gt; Device &lt;span class="m"&gt;004&lt;/span&gt;: ID 12d1:256b Huawei Technologies Co., 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;, 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="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="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 shell pm list packages -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 shell pm dump com.randompackage.android.application &lt;span class="p"&gt;|&lt;/span&gt; grep -A &lt;span class="m"&gt;1&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 shell monkey -p app.package.name -c android.intent.category.LAUNCHER &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 shell am start -n 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 start -a com.example.ACTION_NAME -n 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 install filename.apk
&lt;span class="c1"&gt;#if it had been installed eg. when upgrading&lt;/span&gt;
adb install -r filename.apk
&lt;/pre&gt;&lt;/div&gt;
</content><category term="Computer"></category><category term="linux"></category></entry><entry><title>Why To Use Github</title><link href="https://jnduli.co.ke/why-to-use-github.html" rel="alternate"></link><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: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><category term="github"></category><category term="projects"></category></entry><entry><title>Postgresql Weird Error - Failed To Start</title><link href="https://jnduli.co.ke/postgresql-failed-to-start-error.html" rel="alternate"></link><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: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 systmctl start 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="o"&gt;[&lt;/span&gt;rookie@ArchRookie eventmanagement&lt;span class="o"&gt;]&lt;/span&gt;$ sudo systemctl status postgresql
&lt;span class="o"&gt;[&lt;/span&gt;sudo&lt;span class="o"&gt;]&lt;/span&gt; password &lt;span class="k"&gt;for&lt;/span&gt; rookie:
● postgresql.service - PostgreSQL database 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 systmctl start 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="o"&gt;[&lt;/span&gt;rookie@ArchRookie eventmanagement&lt;span class="o"&gt;]&lt;/span&gt;$ sudo systemctl status postgresql
&lt;span class="o"&gt;[&lt;/span&gt;sudo&lt;span class="o"&gt;]&lt;/span&gt; password &lt;span class="k"&gt;for&lt;/span&gt; rookie:
● postgresql.service - PostgreSQL database server
Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/usr/lib/systemd/system/postgresql.service&lt;span class="p"&gt;;&lt;/span&gt; disabled&lt;span class="p"&gt;;&lt;/span&gt; vendor preset: disabled&lt;span class="o"&gt;)&lt;/span&gt;
Active: failed &lt;span class="o"&gt;(&lt;/span&gt;Result: exit-code&lt;span class="o"&gt;)&lt;/span&gt; since Sun &lt;span class="m"&gt;2017&lt;/span&gt;-02-19 &lt;span class="m"&gt;17&lt;/span&gt;:43:52 EAT&lt;span class="p"&gt;;&lt;/span&gt; 3min 24s ago
Process: &lt;span class="m"&gt;4210&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="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="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="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="m"&gt;19&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;:43:52 ArchRookie 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;: Starting PostgreSQL database server...
Feb &lt;span class="m"&gt;19&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;:43:52 ArchRookie 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;: postgresql.service: Control process exited, &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exited &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="m"&gt;19&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;:43:52 ArchRookie 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;: Failed to start PostgreSQL database server.
Feb &lt;span class="m"&gt;19&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;:43:52 ArchRookie 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;: postgresql.service: Unit entered failed state.
Feb &lt;span class="m"&gt;19&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;:43:52 ArchRookie 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;: postgresql.service: Failed with result &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="o"&gt;[&lt;/span&gt;rookie@ArchRookie eventmanagement&lt;span class="o"&gt;]&lt;/span&gt;$ journalctl -xe
-- The result is failed.
Feb &lt;span class="m"&gt;19&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;:43:52 ArchRookie 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;: Unregistered
Authentication Agent &lt;span class="k"&gt;for&lt;/span&gt; unix-process:4201:1104590 &lt;span class="o"&gt;(&lt;/span&gt;system
Feb &lt;span class="m"&gt;19&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;:43:52 ArchRookie 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;: postgresql.service: Unit
entered failed state.
Feb &lt;span class="m"&gt;19&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;:43:52 ArchRookie 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;: postgresql.service: Failed
with result &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 root
su postgres
initdb --locale &lt;span class="nv"&gt;$LANG&lt;/span&gt; -E UTF8 -D &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><category term="projects"></category><category term="postgresql"></category></entry><entry><title>Solarized Theme</title><link href="https://jnduli.co.ke/solarized-theme.html" rel="alternate"></link><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: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;Plugin &lt;span class="s1"&gt;&amp;#39;altercation/vim-colors-solarized&amp;#39;&lt;/span&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;span class="p"&gt;:&lt;/span&gt;PluginInstall
&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;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;/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;span class="nb"&gt;set&lt;/span&gt; -g @plugin &lt;span class="s1"&gt;&amp;#39;seebi/tmux-colors-solarized&amp;#39;&lt;/span&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;span class="nb"&gt;set&lt;/span&gt; -g @colors-solarized &lt;span class="s1"&gt;&amp;#39;dark&amp;#39;&lt;/span&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><category term="vim"></category><category term="linux"></category></entry><entry><title>Know Thy Editor Well</title><link href="https://jnduli.co.ke/know-thy-editor-well.html" rel="alternate"></link><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: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><category term="vim"></category></entry><entry><title>Changing Menu Icon MinCss</title><link href="https://jnduli.co.ke/changing-menu-icon-mincss.html" rel="alternate"></link><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: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;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;nav&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#000&lt;/span&gt;&lt;span class="p"&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="mi"&gt;10&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt; &lt;span class="kc"&gt;double&lt;/span&gt;&lt;span class="p"&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="mi"&gt;3&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt; &lt;span class="kc"&gt;solid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;content&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="k"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&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="k"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;right&lt;/span&gt;&lt;span class="p"&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="k"&gt;top&lt;/span&gt;&lt;span class="p"&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="k"&gt;width&lt;/span&gt;&lt;span class="p"&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;/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;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;nav&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;&amp;lt;!--everything&lt;/span&gt; &lt;span class="err"&gt;else&lt;/span&gt; &lt;span class="err"&gt;remains&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;same--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&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;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="k"&gt;background&lt;/span&gt;&lt;span class="p"&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;/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><category term="projects"></category></entry><entry><title>Tmux Usage</title><link href="https://jnduli.co.ke/tmux-usage.html" rel="alternate"></link><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: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;sudo pacman -S tmux
&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;tmux
&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;C-b c &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 to the numbered buffer
C-b &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 a hsplit
&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;span class="nb"&gt;bind&lt;/span&gt; -r k &lt;span class="k"&gt;select&lt;/span&gt;-pane -U 
&lt;span class="nb"&gt;bind&lt;/span&gt; -r j &lt;span class="k"&gt;select&lt;/span&gt;-pane -D 
&lt;span class="nb"&gt;bind&lt;/span&gt; -r h &lt;span class="k"&gt;select&lt;/span&gt;-pane -L 
&lt;span class="nb"&gt;bind&lt;/span&gt; -r l &lt;span class="k"&gt;select&lt;/span&gt;-pane -R
&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;C-b h/j/k/l &lt;span class="s2"&gt;&amp;quot; move to window&lt;/span&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;span class="nb"&gt;bind&lt;/span&gt; -r C-k resize-pane -U
&lt;span class="nb"&gt;bind&lt;/span&gt; -r C-j resize-pane -D
&lt;span class="nb"&gt;bind&lt;/span&gt; -r C-h resize-pane -L
&lt;span class="nb"&gt;bind&lt;/span&gt; -r C-l resize-pane -R
&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;C-b C-h/j/k/l
&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;C-n : &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 the windows
&lt;/pre&gt;&lt;/div&gt;</content><category term="Computer"></category><category term="linux"></category></entry><entry><title>Digital Ocean Server Setup</title><link href="https://jnduli.co.ke/digital-ocean-server-setup.html" rel="alternate"></link><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: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;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;/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;span class="go"&gt;ssh-keygen&lt;/span&gt;
&lt;span class="go"&gt;ssh-copy-id root@server-ip&lt;/span&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;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;/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;span class="go"&gt;ssh-keygen&lt;/span&gt;
&lt;span class="go"&gt;ssh-copy-id username@server_ip&lt;/span&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;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;/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;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;/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;span class="go"&gt;sudo apt update&lt;/span&gt;
&lt;span class="go"&gt;sudo apt install nginx&lt;/span&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;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;/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;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;/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;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;/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;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;/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;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;/pre&gt;&lt;/div&gt;</content><category term="Computer"></category><category term="linux"></category><category term="server"></category></entry><entry><title>Org Mode in Vim</title><link href="https://jnduli.co.ke/org-mode-in-vim.html" rel="alternate"></link><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: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;Plugin &lt;span class="s1"&gt;&amp;#39;jceb/vim-orgmode&amp;#39;&lt;/span&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;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;/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;* Plan &lt;span class="k"&gt;for&lt;/span&gt; day 
** Morning tasks [/]
** Server setup [/]
** Research [/]
** Night tasks [/]
&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;* 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;/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;span class="err"&gt;let g:org_agenda_files = [&amp;#39;~/org/index.org&amp;#39;,&amp;#39;~/org/projects.org&amp;#39;]&lt;/span&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><category term="vim"></category></entry><entry><title>Remapping Keyboard Keys(Esc and Caps)</title><link href="https://jnduli.co.ke/remapping-keyboard-keys-esc-caps.html" rel="alternate"></link><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: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;xmodmap -e &lt;span class="s2"&gt;&amp;quot;clear Lock&amp;quot;&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;keycode 9 = Caps_Lock NoSymbol Caps_Lock&amp;quot;&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;keycode 66 = Escape NoSymbol Escape&amp;quot;&lt;/span&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;xmodmap -e &lt;span class="s2"&gt;&amp;quot;remove Lock = Caps_Lock&amp;quot;&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;keycode 9 = Caps_Lock NoSymbol Caps_Lock&amp;quot;&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;keycode 66 = Escape NoSymbol Escape&amp;quot;&lt;/span&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;xmodmap -pke &amp;gt;~/.xmodmap
&lt;span class="c1"&gt;# Add this line to ~/.xinitrc&lt;/span&gt;
xmodmap .xmodmap
&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;span class="c1"&gt;# replaces caps with escape functionality&lt;/span&gt;
setxkbmap -option caps:escape
&lt;span class="c1"&gt;# swaps capslock and escape&lt;/span&gt;
setxkbmap -option caps:swapescape
&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><category term="linux"></category><category term="vim"></category></entry></feed>