<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on Kevin Lui</title>
    <link>https://www.kevinlui.org/posts/</link>
    <description>Recent content in Posts on Kevin Lui</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Mon, 18 Nov 2019 16:22:11 -0700</lastBuildDate>
    
        <atom:link href="https://www.kevinlui.org/posts/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Programming Language Classifier</title>
      <link>https://www.kevinlui.org/posts/langclass/</link>
      <pubDate>Mon, 18 Nov 2019 16:22:11 -0700</pubDate>
      
      <guid>https://www.kevinlui.org/posts/langclass/</guid>
      <description>&lt;p&gt;In this post, I&amp;rsquo;ll explain some of the details that went into
&lt;a href=&#34;http://langclass.kevinlui.org/&#34;&gt;http://langclass.kevinlui.org/&lt;/a&gt;. A fun thing I did was feature importance
recovery after feature hashing. I&amp;rsquo;ll explain that at the end.&lt;/p&gt;
&lt;h1 id=&#34;data-source&#34;&gt;Data source&lt;/h1&gt;
&lt;p&gt;The data was retrieve from the &lt;a href=&#34;https://rosettacode.org/wiki/Rosetta_Code&#34;&gt;Rosetta Code
Project&lt;/a&gt; using this git repo:
&lt;a href=&#34;https://github.com/acmeism/RosettaCodeData&#34;&gt;https://github.com/acmeism/RosettaCodeData&lt;/a&gt;. The features are code snippets
and the labels are programming languages.&lt;/p&gt;
&lt;h1 id=&#34;tokenization&#34;&gt;Tokenization&lt;/h1&gt;
&lt;p&gt;We consider 2 different tokenizers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;character-level tokenization.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;print(&amp;#39;Hello World&amp;#39;) ==&amp;gt; [&amp;#39;p&amp;#39;, &amp;#39;r&amp;#39;, &amp;#39;i&amp;#39;, &amp;#39;n&amp;#39; &amp;#39;t&amp;#39;, &amp;#39;(&amp;#39;, ...]
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;split on non-alphanumerical.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;print(&amp;#39;Hello World&amp;#39;) ==&amp;gt; [&amp;#39;print&amp;#39;, &amp;#39;(&amp;#39;, &amp;#39;Hello&amp;#39;, &amp;#39;World&amp;#39;, &amp;#39;)&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;vectorization&#34;&gt;Vectorization&lt;/h1&gt;
&lt;p&gt;After tokenizing, we consider consider 1-grams followed by feature hashing
modulo 4098. We also do the same with 2-grams.&lt;/p&gt;
&lt;h1 id=&#34;classifier&#34;&gt;Classifier&lt;/h1&gt;
&lt;p&gt;We use &lt;a href=&#34;https://lightgbm.readthedocs.io/en/latest/&#34;&gt;lightgbm&lt;/a&gt; with default
parameters. There&amp;rsquo;s a lot of tuning to be done but that wasn&amp;rsquo;t my main interest
so I&amp;rsquo;m putting it off.&lt;/p&gt;
&lt;h1 id=&#34;feature-importance&#34;&gt;Feature Importance&lt;/h1&gt;
&lt;p&gt;A fun thing I did was feature importance extraction despite feature hashing.
After training a tree-based model on feature-hashed inputs, you can normally
only determine the feature importance of the hash values. For example, you
might discover that the hash 123 has high importance. But this does not tell
you which one of our original tokens has high importance. You can determine
which tokens hashes to 123 but it could be the case that many tokens share the
same hash value. In the next section, we share an idea for recovering the
feature importance of the original tokens.&lt;/p&gt;
&lt;p&gt;The top features for character-level 2-grams are:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[&amp;#39;;\n&amp;#39;, &amp;#39;)\n&amp;#39;, &amp;#39; (&amp;#39;, &amp;#39;, &amp;#39;, &amp;#39; =&amp;#39;, &amp;#39;= &amp;#39;, &amp;#39;t(&amp;#39;, &amp;#39;t &amp;#39;, &amp;#39;in&amp;#39;, &amp;#39;# &amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The top features for 1-grams where we split on non-alphanumericals are:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[&amp;#39;;&amp;#39;, &amp;#39;=&amp;#39;, &amp;#39;.&amp;#39;, &amp;#39;:&amp;#39;, &amp;#39;print&amp;#39;, &amp;#39;,&amp;#39;, &amp;#39;&amp;#34;&amp;#39;, &amp;#39;#&amp;#39;, &amp;#39;)&amp;#39;, &amp;#39;-&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The most importance feature in both cases contains a semi-colon. This is
unsurprising since some programming languages seldomly use semi-colons (for
example, Python) while some programming languages use semi-colons extensively
(for example, C).&lt;/p&gt;
&lt;h1 id=&#34;mathematical-heuristic&#34;&gt;Mathematical Heuristic&lt;/h1&gt;
&lt;p&gt;This technique is mainly inspired by bloom-filters. For ease of exposition,
we&amp;rsquo;ll focus on the character-level 2-grams case. Let $X$ be the space of
character-level 2-grams, $Y$ be the hashed space, and $H_1, H_2, H_3:X \to Y$
be 3 different hash functions. In our implementation, we take $H_i$ to be the
murmur3 hash with seed $i$.&lt;/p&gt;
&lt;p&gt;For $x\in X$, let $f_x$ be the feature importance of $x$ if we were to train
our model using unhashed features. For $y\in Y$ and $t\in \{1,2,3\}$, let
$g_y ^t$ be the feature importance of $y$ using the hash function $H_t$. For
our heuristic, we assume that $g_y ^t$ is approximately $\sum_{x\in H_t
^{-1}(y)} f_x$.&lt;/p&gt;
&lt;p&gt;Our model is trained on the hashed space so we have access to $g_y ^t$. Our
goal is to understand $f_x$. We can of course approximate the solution to a
massive linear system so try to recover $f_x$ but what we&amp;rsquo;re really interested
is a ranking of $f_x$. So do this, we&amp;rsquo;ll use the geometric-mean of the hashed
values. In particular, let $F_x = (\prod_{t=1} ^3 g_{H_t(x)} ^t)^{1
/3}$. Then we can show that if $f_x &amp;gt; f_y$, then
$\mathbb{E}(F_x)&amp;gt;\mathbb{E}(F_y)$.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Alerting long commands in zsh</title>
      <link>https://www.kevinlui.org/posts/alerting_long_commands_in_zsh/</link>
      <pubDate>Sat, 31 Aug 2019 19:35:54 -0700</pubDate>
      
      <guid>https://www.kevinlui.org/posts/alerting_long_commands_in_zsh/</guid>
      <description>&lt;p&gt;Update (2019-10-03): I fleshed this out into a plugin! Check it out
&lt;a href=&#34;https://github.com/kevinywlui/zlong_alert.zsh&#34;&gt;https://github.com/kevinywlui/zlong_alert.zsh&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I often find myself running commands that take a long time and then coming back
to it later. For example, when I&amp;rsquo;m running a long computation for my research
or when I&amp;rsquo;m building a package. I recently discovered this &lt;a href=&#34;https://gist.github.com/oknowton/8346801&#34;&gt;zbell
gist&lt;/a&gt; which seems to be almost
exactly what I want! I&amp;rsquo;m trying to learn more shell scripting so I&amp;rsquo;m going to
reimplement this and explain what I&amp;rsquo;m doing. The final version will be this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Ignore commands if they start with the follow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_ignore_cmds&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;vim ssh&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Define what a long duration is&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_duration&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Need to set an initial timestamps otherwise, we&amp;#39;ll be comparing an empty&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# string with an integer.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_timestamp&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$EPOCHSECONDS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Define the alerting function, do the text processing here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_alert_func&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local cmd&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local secs&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local ftime&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;printf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%dh:%dm:%ds\n&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;$secs &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3600&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;$secs &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3600&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;$secs &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    notify-send &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Done: &lt;/span&gt;$1&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Time: &lt;/span&gt;$ftime&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_alert_pre&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zlong_timestamp&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$EPOCHSECONDS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zlong_last_cmd&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_alert_post&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local duration&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;$EPOCHSECONDS &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; $zlong_timestamp&lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local lasted_long&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;$duration &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; $zlong_duration&lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local cmd_head&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo $zlong_last_cmd | cut -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; -f 1&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; $lasted_long -gt &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ! -z $zlong_last_cmd &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ! *&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$cmd_head&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;*&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;zlong_ignore_cmds &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        zlong_alert_func $zlong_last_cmd duration
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zlong_last_cmd&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add-zsh-hook preexec zlong_alert_pre
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add-zsh-hook precmd zlong_alert_post&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&#34;overview&#34;&gt;Overview&lt;/h1&gt;
&lt;p&gt;The goal of this script is to alert me whenever a command, that has taken over
60 seconds, is complete. I will be use &lt;code&gt;notify-send&lt;/code&gt; to alert me and also send
a &lt;a href=&#34;https://en.wikipedia.org/wiki/Bell_character&#34;&gt;bell character&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For my particular desktop setup, &lt;code&gt;notify-send&lt;/code&gt; will alert me via &lt;code&gt;dunst&lt;/code&gt; and
the bell will set my &lt;code&gt;kitty&lt;/code&gt; terminal to urgent which &lt;code&gt;i3wm&lt;/code&gt; will pick up on
and turn the workspace indicator red.&lt;/p&gt;
&lt;p&gt;So my alert function will send me the command that was ran, the duration
formatted nicely, and a bell character.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_alert_func&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local cmd&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local secs&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local ftime&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;printf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%dh:%dm:%ds\n&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;$secs &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3600&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;$secs &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3600&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt;$secs &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    notify-send &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Done: &lt;/span&gt;$1&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Time: &lt;/span&gt;$ftime&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;timing-commands&#34;&gt;Timing commands&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;zsh/datetime&lt;/code&gt; module gives us the &lt;code&gt;EPOCHSECONDS&lt;/code&gt; parameter which is the
number of seconds since the unix epoch. To determine the duration, we just need
to subtract &lt;code&gt;EPOCHSECONDS&lt;/code&gt; when the command is complete from &lt;code&gt;EPOCHSECONDS&lt;/code&gt;
when the command started. We will use &lt;code&gt;zsh&lt;/code&gt; hooks for this.&lt;/p&gt;
&lt;h2 id=&#34;zsh-hooks&#34;&gt;Zsh hooks&lt;/h2&gt;
&lt;p&gt;One of the advantages of &lt;code&gt;zsh&lt;/code&gt; over &lt;code&gt;bash&lt;/code&gt; is that you get
&lt;a href=&#34;http://zsh.sourceforge.net/Doc/Release/Functions.html#Hook-Functions&#34;&gt;hooks&lt;/a&gt;.
For this script, we&amp;rsquo;re interested in&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;preexec&lt;/code&gt; which &amp;lsquo;&amp;rsquo;executed just after a command has been read and is about to
be executed.&amp;rsquo;&#39;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;precmd&lt;/code&gt; which &amp;lsquo;&amp;rsquo;executed before each prompt.&amp;rsquo;&#39;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_alert_pre&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zlong_timestamp&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$EPOCHSECONDS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zlong_last_cmd&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zlong_alert_post&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local duration&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt; $EPOCHSECONDS &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; $zlong_timestamp &lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    local lasted_long&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$((&lt;/span&gt; $duration &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; $zlong_duration &lt;span style=&#34;color:#66d9ef&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; $lasted_long -gt &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        zlong_alert_func $zlong_last_cmd duration
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add-zsh-hook preexec zlong_alert_pre
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;add-zsh-hook precmd zlong_alert_post&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;ignore-some-commands&#34;&gt;Ignore some commands&lt;/h2&gt;
&lt;p&gt;I use &lt;code&gt;vim&lt;/code&gt; and &lt;code&gt;ssh&lt;/code&gt; often and it doesn&amp;rsquo;t really make sense to count them as a
long command. I store the commands I want to ignore in a comma separated list
at the top, I can extract the head of a command as follows:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd_head&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\$&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;echo $zlong_last_cmd | cut -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; -f 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
and substring testing is done using the star wildcard&lt;/p&gt;
&lt;p&gt;&lt;code&gt;*&amp;quot;$cmd_head&amp;quot;*==zlong_ignore_cmds&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;fixing-a-zbell-bug&#34;&gt;Fixing a zbell bug&lt;/h2&gt;
&lt;p&gt;In the &lt;code&gt;zbell&lt;/code&gt; gist, there was a super annoying bug! If you run &lt;code&gt;ls&lt;/code&gt;, wait long
enough, then press ctrl-c, it&amp;rsquo;ll alert you! This is because &lt;code&gt;preexec&lt;/code&gt; did not
get a chance to run again but &lt;code&gt;precmd&lt;/code&gt; did so it&amp;rsquo;ll count the duration as the
time since the &lt;code&gt;ls&lt;/code&gt; command. This was fix by setting &lt;code&gt;zlong_last_cmd&lt;/code&gt; to be the
empty string at the end of &lt;code&gt;preexec&lt;/code&gt; then checking to see if the string is
non-empty before sending it to the alert function.&lt;/p&gt;
&lt;h1 id=&#34;alternatives&#34;&gt;Alternatives&lt;/h1&gt;
&lt;p&gt;One alternative to alerting the end of long commands that I should mention is
using Pushbullet. Pushbullet is an app that I have installed on my phone that
can send me notifications. The best part about Pushbullet is that it has an
API. I&amp;rsquo;ve use &lt;a href=&#34;https://github.com/Red5d/pushbullet-bash&#34;&gt;https://github.com/Red5d/pushbullet-bash&lt;/a&gt; to send me an alert of
my phone whenever a long computation I was doing for my research has finished.&lt;/p&gt;
&lt;p&gt;Another cool &lt;code&gt;zsh&lt;/code&gt; feature is &lt;code&gt;REPORTTIME&lt;/code&gt;. This won&amp;rsquo;t alert you but it&amp;rsquo;ll tell
you how long a command has run for. For example, by setting &lt;code&gt;REPORTTIME=3&lt;/code&gt;,
&lt;code&gt;zsh&lt;/code&gt; will tell me the run duration of any command that takes more than 3
second.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Automatic Vim PlugUpdate</title>
      <link>https://www.kevinlui.org/posts/automatic_vimplug_update/</link>
      <pubDate>Sun, 04 Aug 2019 21:58:21 -0700</pubDate>
      
      <guid>https://www.kevinlui.org/posts/automatic_vimplug_update/</guid>
      <description>&lt;p&gt;This post was inspired by this &lt;a href=&#34;https://www.reddit.com/r/vim/comments/clf6l2/vimplug_run_plugupdate_every_week_automatically/&#34;&gt;Reddit
thread&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I use &lt;a href=&#34;https://github.com/junegunn/vim-plug&#34;&gt;vim-plug&lt;/a&gt; to handle my vim
plugins and I want to keep my plugins up-to-date. Ideally, this would be done
automatically but I don&amp;rsquo;t want to suddenly have a broken vim setup. Luckily,
&lt;code&gt;vim-plug&lt;/code&gt; comes with a snapshot feature.&lt;/p&gt;
&lt;p&gt;I save the following as &lt;code&gt;~/bin/vimplug_update&lt;/code&gt;.
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#! /usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;vim_cmd&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nvim&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BACKUP_DIR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$HOME&lt;span style=&#34;color:#e6db74&#34;&gt;/.vimplug_snapshots&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BACKUP_FILE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$BACKUP_DIR&lt;span style=&#34;color:#e6db74&#34;&gt;/snapshot_&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;date +&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%Y-%m-%d-%H%M%S&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.vim&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$BACKUP_DIR&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$vim_cmd -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PlugSnapshot &lt;/span&gt;$BACKUP_FILE&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; +qa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$vim_cmd +PlugUpdate +qa&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Then I set a daily cron job by running &lt;code&gt;crontab -e&lt;/code&gt; and writing
&lt;code&gt;@daily ~/bin/vimplug_update&lt;/code&gt;. If I ever have to restore my settings, I run&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;vim -S snapshot_2019-08-05-085852.vim
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    <item>
      <title>Developing for Sagemath</title>
      <link>https://www.kevinlui.org/posts/developing_for_sagemath/</link>
      <pubDate>Thu, 01 Aug 2019 16:22:11 -0700</pubDate>
      
      <guid>https://www.kevinlui.org/posts/developing_for_sagemath/</guid>
      <description>&lt;p&gt;For my first post, I&amp;rsquo;ll explain how to begin developing for
&lt;a href=&#34;https://sagemath.org&#34;&gt;Sagemath&lt;/a&gt;. This post is essentially a
&lt;a href=&#34;https://gist.github.com/kevinywlui/6c494f8dbbb2c667d07fc101e8d3b19c/&#34;&gt;gist&lt;/a&gt;
that I shared with members of the UW Sage Seminar. This is a short version of
the official guide.&lt;/p&gt;
&lt;h1 id=&#34;official-sagemath-guide&#34;&gt;Official Sagemath guide&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://doc.sagemath.org/html/en/developer/index.html&#34;&gt;https://doc.sagemath.org/html/en/developer/index.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id=&#34;setting-up-local-development-copy&#34;&gt;Setting up local development copy&lt;/h1&gt;
&lt;p&gt;The first task will be to obtain a local development copy of Sagemath.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clone Sagemath and checkout the develop branch&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;git clone https://github.com/sagemath/sage
cd ~/sage
git checkout develop
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;Build Sagemath. I had access to a 48 thread machine so I used all 48 threads.
It was a shared computer so I also assigned the build process a nice level of
19. This will take between 30 minutes to 6 hours so we&amp;rsquo;ll move on to the next
step while this is going.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd ~/sage
export MAKE=&amp;#39;make -j 48&amp;#39;
nice -n 19 make build
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h1 id=&#34;developing-via-trac&#34;&gt;Developing via trac&lt;/h1&gt;
&lt;p&gt;Sagemath development is done through the Sagemath trac server:
&lt;a href=&#34;https://trac.sagemath.org/&#34;&gt;https://trac.sagemath.org/&lt;/a&gt;. We now setup our local git repository to interact
with this server easily.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The new way to get a Sagemath-trac account is to use your Github account.
Click on &amp;ldquo;Github Login&amp;rdquo; on the main Sagemath-trac page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Sagemath people made a cool tool called &lt;code&gt;git-trac-command&lt;/code&gt;
(&lt;a href=&#34;https://github.com/sagemath/git-trac-command&#34;&gt;https://github.com/sagemath/git-trac-command&lt;/a&gt;). This tool provides the &lt;code&gt;git trac&lt;/code&gt; subcommand helps our local git repository interface with the
Sagemath-trac server. Install this package.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd
git clone https://github.com/sagemath/git-trac-command
cd ~/git-trac-command
python setup.py install --user
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;We can now authenticate using username/token. The username is list on the
Sagemath-trac page. It is also &lt;code&gt;gh.yourgithubname&lt;/code&gt;. The token is listed under
account preferences.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd ~/sage
git trac config --user USERNAME --token TOKEN
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;We also need to authenticate with ssh keys. So first generate the keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd
ssh-keygen # follow the prompts or spam &amp;lt;ENTER&amp;gt;
cat .ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;The output of the previous command is your ssh public key. Copy this over to
your account preferences under ssh keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id=&#34;make-a-ticket&#34;&gt;Make a ticket!!&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Hit the new ticket button.&lt;/li&gt;
&lt;li&gt;Fill in what it asks.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id=&#34;checkout-the-ticket&#34;&gt;Checkout the ticket&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Now checkout the ticket in your local development copy.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd ~/sage
git trac checkout &amp;lt;ticket number&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h1 id=&#34;make-a-commit&#34;&gt;Make a commit&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Perform some edits.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add filename&lt;/code&gt; to tell git to track these edits.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git commit -m &amp;quot;&amp;lt;one line description&amp;gt;&amp;quot;&lt;/code&gt; to make a commit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git trac push&lt;/code&gt; to send to the trac server.&lt;/li&gt;
&lt;li&gt;When ready, modify the ticket and set to &amp;ldquo;Need Review&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
