<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>NODENEXUS</title>
    <description>A Blog by Collin Stedman</description>    
    <link>http://blog.nodenexus.com</link>
    <atom:link href="http://blog.nodenexus.com/feed" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Average Time to Check If an Array Is Sorted</title>
        <description><![CDATA[&lt;p&gt;It’s always a pleasure to find interesting problems hiding in seemingly mundane places. Recently a colleague of mine posed the following twist on a basic algorithms question. It’s easy to see that the worst-case performance to check if a random \(n\)-length array is sorted is \(O(n)\). But what is the &lt;em&gt;average&lt;/em&gt; performance? Is it still linear? Sublinear? Is it a function of the length at all?&lt;/p&gt;

&lt;p&gt;Throughout this post, we’ll assume that all arrays are drawn uniformly at random from the set of \(n\)-length arrays containing the numbers \(1\) through \(n\) with no duplicates. Of course, if an adversary is providing the input arrays, you should expect the average and worst cases to be the same.&lt;/p&gt;

&lt;p&gt;Let’s start out by writing out exactly what we’re trying to compute. We check if a random array is sorted by performing comparisons between each adjacent pair of elements, returning either when we find an inversion or reach the end. The average performance is equal to the expected number of comparisons needed to find the first inversion in a random array. That is,&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;E[C] = \sum_{i=1}^{n-1} P(c_i) * i&lt;/script&gt;

&lt;p&gt;where \(C\) is the random variable for the number of comparisons performed, \(c_i\) is the index (starting at one) of the first inversion, \(P(c_i)\) is the probability of seeing it at that location, and \(n\) is the array length.&lt;/p&gt;

&lt;p&gt;That’s the simple expression, but for reasons that I’ll explain momentarily, we’ll rewrite it using conditional probabilities:&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;\small E[C] = P(c_1) + P(\overline{c_1}) * \bigg( P(c_2|\overline{c_1}) * 2 + P(\overline{c_2}|\overline{c_1}) * \Big(... + P(\overline{c_{n-2}}|\overline{c_1},...,\overline{c_{n-3}}) * (n-1)\Big)\bigg)&lt;/script&gt;

&lt;p&gt;where \(P(\overline{c_i})\) is the complement of \(P(c_i)\), or \(1 - P(c_i)\). We can see that quations \((1)\) and \((2)\) are equal by distributing the complementary terms, working from the outside in.&lt;/p&gt;

&lt;p&gt;Now we need to find a way to compute the values for the probabilities. If the array were small, say four elements long, we could just enumerate all sorted subarrays and count how many of the remaining choices of next element introduce inversions. The subarrays are sorted because, as the conditional probabilities represent, we are interested in the likelihood of seeing the &lt;em&gt;first&lt;/em&gt; inversion when we append the next element. The conditional probabilities save us from having to enumerate subarrays beyond their first inversions, saving a little time and memory in a program.&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;% &lt;![CDATA[
\notag
\begin{array}{c|c|c}
  \text{Subarray} &amp; \text{# Choices} &amp; \text{# Causing Inversions} \\
  \hline
  [1] &amp; 3\ (2, 3, 4) &amp; 0 \\
  [2] &amp; 3\ (1, 3, 4) &amp; 1\ (1) \\
  [3] &amp; 3\ (1, 2, 4) &amp; 2\ (1, 2) \\
  [4] &amp; 3\ (1, 2, 3) &amp; 3\ (1, 2, 3) \\
  \hline
  \text{Section Total} &amp; 12 &amp; 6 \\
  \hline
  [1,2] &amp; 2\ (3, 4) &amp; 0 \\
  [1,3] &amp; 2\ (2, 4) &amp; 1\ (2) \\
  [1,4] &amp; 2\ (2, 3) &amp; 2\ (2, 3) \\
  [2,3] &amp; 2\ (1, 4) &amp; 1\ (1) \\
  [2,4] &amp; 2\ (1, 3) &amp; 2\ (1, 3) \\
  [3,4] &amp; 2\ (1, 2) &amp; 2\ (1, 2) \\
  \hline
  \text{Section Total} &amp; 12 &amp; 8 \\
  \hline
  [1,2,3] &amp; 1\ (4) &amp; 0 \\
  [1,2,4] &amp; 1\ (3) &amp; 1\ (3) \\
  [1,3,4] &amp; 1\ (2) &amp; 1\ (2) \\
  [2,3,4] &amp; 1\ (1) &amp; 1\ (1) \\
  \hline
  \text{Section Total} &amp; 4 &amp; 3 \\
\end{array} %]]&gt;&lt;/script&gt;

&lt;p&gt;Of course, we want to answer the question for much larger arrays, so let’s write a quick and dirty script:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;table style=&quot;border-spacing: 0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot; style=&quot;text-align: right&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env python&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# inversion_count.py&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;collections&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deque&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;arr_length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# Use a deque like a linked list&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;states&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deque&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;states&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;progress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;choices&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;results_by_length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;states&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;states&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;popleft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;state_length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;progress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;# If we haven't seen a subarray of this length, add category to results&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state_length&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results_by_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;results_by_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;inverted&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;choices&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;results_by_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;progress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;results_by_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;inverted&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;c&quot;&gt;# We only add a new state if our progress in sorted...&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;choices&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;c&quot;&gt;# And there are still choices available to the new state&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;new_progress&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;progress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;new_progress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                    &lt;span class=&quot;n&quot;&gt;new_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;s&quot;&gt;&quot;progress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_progress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;s&quot;&gt;&quot;choices&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;choices&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;states&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results_by_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iteritems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;d: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;d / &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;d&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;inverted&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Usage error: Expects desired array length as an argument&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;pre class=&quot;terminal&quot;&gt;&lt;code&gt;$ chmod +x inversion_count.py
$ ./inversion_count.py 3
1: 3/6
2: 2/3
$ ./inversion_count.py 5
1: 10 / 20
2: 20 / 30
3: 15 / 20
4: 4 / 5
$ ./inversion_count.py 10
1: 45 / 90
2: 240 / 360
3: 630 / 840
4: 1008 / 1260
5: 1050 / 1260
6: 720 / 840
7: 315 / 360
8: 80 / 90
9: 9 / 10
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see see that the probability of seeing the first inversion on the \(i\)th comparison follows the sequence&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;\notag \frac{1}{2}, \frac{2}{3}, \frac{3}{4}, \frac{4}{5}...&lt;/script&gt;

&lt;p&gt;regardless of the length of the array. So we can plug back into equation \((2)\):&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;E[C] = \frac{1}{2} + \frac{1}{2} \bigg( \frac{2}{3} * 2 + \frac{1}{3} \Big( \frac{3}{4} * 3 + \frac{1}{4} \big(... + \frac{1}{n-2} * (n - 1) \big) \Big) \bigg)&lt;/script&gt;

&lt;p&gt;Now we distribute the fraction multiplication across the nested expressions and get the coefficient sequence&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;\notag \frac{1}{2}, \frac{1}{3}, \frac{1}{8}, \frac{1}{30}, \frac{1}{144}, \frac{1}{840} ...&lt;/script&gt;

&lt;p&gt;Luckily enough for people like myself who don’t see the pattern immediately, the Online Encyclopedia of Integer Sequences has &lt;a href=&quot;http://oeis.org/A001048&quot;&gt;an entry&lt;/a&gt; for this sequence&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;a(n) = \frac{n}{(n+1)!}&lt;/script&gt;

&lt;p&gt;Thus we have everything we need to rewrite equation \((2)\) cleanly:&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;E[C] = \sum_{i=1}^{n-1} \frac{n^2}{(n+1)!}&lt;/script&gt;

&lt;p&gt;Expanding out the terms, we can see the sum converges to a familiar and unexpected value.&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;E[C] = \frac{1}{2} + \frac{2}{3} + \frac{3}{8} + \frac{4}{30} + \frac{5}{144} + \frac{6}{840} + ... \approx 1.718281 = e - 1&lt;/script&gt;

&lt;p&gt;I don’t claim to understand why Euler’s Number is involved, but I find it both curious and convenient that the expected time it takes to check for array sortedness is constant. Even as your arrays grow extremely large, you can rest easy knowing your function &lt;code class=&quot;highlighter-rouge&quot;&gt;isSorted(arr)&lt;/code&gt; is unlikely to take anywhere close to linear time.&lt;/p&gt;

&lt;script src=&quot;https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;

&lt;script typ=&quot;text/x-mathjax-config&quot;&gt;
MathJax.Hub.Config({
  TeX: { equationNumbers: { autoNumber: &quot;all&quot; } }
});
&lt;/script&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Note that OEIS has the equation for the sequence in the numerator, so we use the inverse. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
]]></description>
        <pubDate>Sat, 29 Oct 2016 00:00:00 +0000</pubDate>
        <link>http://blog.nodenexus.com/2016/10/29/average-array-issorted-performance/</link>
        <guid isPermaLink="true">http://blog.nodenexus.com/2016/10/29/average-array-issorted-performance/</guid>
      </item>
    
      <item>
        <title>Shell Fu in zsh</title>
        <description><![CDATA[&lt;p&gt;Programmers are a lot like exotic car owners. We live for the cutting edge and the most efficient solutions. We’re not afraid of a little (or a lot) of DIY. Some of us are actually crazy enough to &lt;a href=&quot;https://www.youtube.com/watch?v=LrsN3r_gVJU&quot;&gt;cool our rigs with liquid nitrogen in the name of clock-speed records&lt;/a&gt;. I’m sure supercar enthusiasts would understand.&lt;/p&gt;

&lt;p&gt;Whereas auto modding is all in the physical world, however, computer performance is a function of hardware and software tuning. Despite being the proud builder of my own (air-cooled) gaming rig, I’ll be the first to admit that I don’t really know too much about hardware hackery. I do, however, have some tips when it comes to fine-tuning your development environment. Let me share with you some secrets of shell fu.&lt;/p&gt;

&lt;p&gt;At a university where many (most?) classes use Java, shell fu technique seems &lt;a href=&quot;http://en.wikipedia.org/wiki/Bernoulli_distribution&quot;&gt;Bernoulli-distributed&lt;/a&gt;: you either customize to your heart’s desire or not at all. That means that many people could increase their productivity in the shell with just a couple of aliases and other simple tricks. I’ll start with the low-hanging fruit and then move on to some more advanced tweaks for those of you who have seen some things before.&lt;/p&gt;

&lt;h2 id=&quot;oh-my-zsh&quot;&gt;Oh. My. Zsh.&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Bash_%28Unix_shell%29&quot;&gt;bash (the Bourne-again shell)&lt;/a&gt; is probably the world’s most popular shell. Unless you’ve changed it yourself, your machine’s default shell is almost certainly bash. As the de facto standard, bash is a time-tested option with good documentation. That being said, if you’re not afraid of new things, I highly suggest that you make a leap of faith and make the Z shell your default.&lt;/p&gt;

&lt;p&gt;What’s the difference between zsh and bash, you ask? zsh was built to be a csh replacement with support for many ksh features, particularly autocompletion. Its scripting language is similar to bash’s with various syntactic quirks.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Unless you have a lot of experience with many different shells, you probably won’t notice the behind-the-scenes distinctions. What you will notice, however, is the incredible out-of-the-box user experience that zsh provides over bash.&lt;/p&gt;

&lt;p&gt;Simply put, zsh makes it incredibly easy to execute commands and navigate directories. With built in features like global aliases (put aliases inside other expressions!) and filepath completion (press &lt;kbd&gt;tab&lt;/kbd&gt; to toggle through each potential match), you’ll wonder how you ever tolerated using a terminal without them. You’ll &lt;em&gt;cringe&lt;/em&gt; the next time you try to use your friend’s shell and it’s bash.&lt;/p&gt;

&lt;p&gt;There are so many excellent features packed into zsh that I can’t possibly cover them all here. In fact, I still haven’t discovered everything zsh has to offer. The slides below cover the absolute essentials you should know when you upgrade from bash.&lt;/p&gt;

&lt;div class=&quot;flex&quot;&gt;
  &lt;div&gt;
    &lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/16194692&quot; width=&quot;425&quot; height=&quot;355&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen=&quot;&quot;&gt; &lt;/iframe&gt;
    &lt;div style=&quot;margin-bottom:5px&quot;&gt;
      &lt;strong&gt; &lt;a href=&quot;//www.slideshare.net/jaguardesignstudio/why-zsh-is-cooler-than-your-shell-16194692&quot; title=&quot;Why Zsh is Cooler than Your Shell&quot; target=&quot;_blank&quot;&gt;Why Zsh is Cooler than Your Shell&lt;/a&gt; &lt;/strong&gt; from &lt;strong&gt;&lt;a href=&quot;//www.slideshare.net/jaguardesignstudio&quot; target=&quot;_blank&quot;&gt;jaguardesignstudio&lt;/a&gt;&lt;/strong&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;In the event that you skipped the slides above (for shame!), let me draw your attention to &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh&quot;&gt;Oh My Zsh&lt;/a&gt;. In their own words:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;
    Oh My Zsh is an open source, community-driven framework for managing your zsh configuration. That sounds boring. Let's try this again.

    &lt;strong&gt;Oh My Zsh is a way of life!&lt;/strong&gt; Once installed, your terminal prompt will become the talk of the town &lt;em&gt;or your money back!&lt;/em&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you install Oh My Zsh, you’ll be able to use dozens of premade shell prompts (“themes”) and functions (“plugins”), all located in ~/.oh-my-zsh. Want a flashy shell befitting a true hacker? One of the 138 included themes in ~/.oh-my-zsh/themes is bound to suit your needs. Are you tired of navigating back and forth between the shell and browser to create a new GitHub repository? &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/github&quot;&gt;There’s a plugin for that&lt;/a&gt;. In fact, there are &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins-Overview&quot;&gt;so many plugins that somebody made a list&lt;/a&gt;. Swapping themes or plugins is as easy as changing a line in your .zshrc file.&lt;/p&gt;

&lt;p&gt;Oh My Zsh is also easy to extend yourself; just put your own scripts, themes, and plugins in ~/.oh-my-zsh/custom. Oh My Zsh will automatically source the scripts, though you’ll still have to change your .zshrc to specify the use of custom themes and plugins. Note that custom plugins and themes go in ~/.oh-my-zsh/custom/plugins and ~/.oh-my-zsh/custom/themes, respectively.&lt;/p&gt;

&lt;p&gt;Now let’s see some custom enhancements. While everything that follows is written from the perspective of a zsh user, the lessons (and even most of the code) can be adapted for bash.&lt;/p&gt;

&lt;h2 id=&quot;the-pearl-within&quot;&gt;The Pearl Within&lt;/h2&gt;

&lt;p&gt;The first thing most people notice about zsh is its support for better user prompts than what bash can provide. Whereas bash allows prompt customization via the &lt;code class=&quot;highlighter-rouge&quot;&gt;PS1&lt;/code&gt; variable, zsh provides two variables: &lt;code class=&quot;highlighter-rouge&quot;&gt;PROMPT&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;RPROMPT&lt;/code&gt;. As you might guess, &lt;code class=&quot;highlighter-rouge&quot;&gt;PROMPT&lt;/code&gt; is the replacement for &lt;code class=&quot;highlighter-rouge&quot;&gt;PS1&lt;/code&gt;, while &lt;code class=&quot;highlighter-rouge&quot;&gt;RPROMPT&lt;/code&gt; is a second, right-justified prompt. That’s right, now you can have your prompt display information on both sides of the window!&lt;/p&gt;

&lt;p&gt;An awful lot has been already been written about shell prompt customization. For example, Steve Losh has a wonderful blog post detailing how to &lt;a href=&quot;http://stevelosh.com/blog/2010/02/my-extravagant-zsh-prompt/&quot;&gt;create a prompt complete with a battery indicator&lt;/a&gt;. My own prompt is adapted from Losh’s example. It looks like this:&lt;/p&gt;

&lt;pre class=&quot;terminal&quot;&gt;&lt;code&gt;&lt;strong&gt;cstedman&lt;/strong&gt;&lt;span style=&quot;color: #ee7f2d; font-size: 100%;&quot;&gt;@&lt;/span&gt;&lt;strong&gt;nebulose&lt;/strong&gt; &lt;span style=&quot;color: #ee7f2d; font-size: 100%;&quot;&gt;➤&lt;/span&gt;  &lt;span style=&quot;color: #aaa; font-size: 100%;&quot;&gt;LVL 1&lt;/span&gt; &lt;span class=&quot;line&quot; style=&quot;color: #ee7f2d; font-size: 100%;&quot;&gt;--------------------------------------------------------&lt;/span&gt; &lt;span class=&quot;date&quot; style=&quot;color: #aaa; font-size: 100%;&quot;&gt;Tue Apr 07 2015&lt;/span&gt; &lt;span style=&quot;color: #ee7f2d; font-size: 100%;&quot;&gt;➤&lt;/span&gt;  &lt;span class=&quot;time&quot; style=&quot;color: #aaa; font-size: 100%;&quot;&gt;17:00&lt;/span&gt;
&lt;span style=&quot;color: #ee7f2d; font-size: 100%;&quot;&gt;~&lt;/span&gt; &lt;span style=&quot;color: red; font-size: 100%;&quot;&gt;±&lt;/span&gt; &lt;span style=&quot;color: yellow; font-size: 100%&quot;&gt;蛇&lt;/span&gt; &lt;span style=&quot;color: #53d646; font-size: 100%;&quot;&gt;✓&lt;/span&gt; &lt;span class=&quot;cursor&quot; style=&quot;color: #aaa; font-size: 100%;&quot;&gt;█&lt;/span&gt;                  &lt;span class=&quot;spaces&quot;&gt;                                                        &lt;/span&gt;                &lt;span class=&quot;battery&quot; style=&quot;color: yellow; font-size: 100%;&quot;&gt;▸▸▸▸▸▸▹▹▹▹&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;script type=&quot;application/javascript&quot; src=&quot;/js/posts/extending-zsh-functionality.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Here is the corresponding .zsh-theme file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;table style=&quot;border-spacing: 0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot; style=&quot;text-align: right&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;# Variables for precmd&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;LONG_HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;hostname&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SHORT_HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LONG_HOST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(ws&lt;/span&gt;:.:&lt;span class=&quot;p&quot;&gt;)1]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;HOST_LEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${#&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SHORT_HOST&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;LSCOLORS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hxfxcxdxHxegedabagacad
&lt;span class=&quot;nv&quot;&gt;BAT_CHARGE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/Users/cstedman/Code/Shell/config/batcharge.py'&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Precommand which runs before redrawing the prompt&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;precmd&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;RPROMPTGOAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(z)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$BAT_CHARGE&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class=&quot;k&quot;&gt;)}&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;RPROMPT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$RPROMPTGOAL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[1]%}&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$RPROMPTGOAL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[2]%{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$RPROMPTGOAL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[3]%}&quot;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;LINENUM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;i &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0; i &amp;lt; &lt;span class=&quot;nv&quot;&gt;$COLUMNS&lt;/span&gt; - 45 - &lt;span class=&quot;nv&quot;&gt;$HOST_LEN&lt;/span&gt;; i++&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LINENUM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LINENUM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&quot;&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;done
  if &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; -n &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$VIRTUAL_ENV&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; ; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PROMPT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_OLD_VIRTUAL_PS1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Indicate that the CWD is a git or mercurial repository&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;vcsCheck &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    git branch &amp;gt;/dev/null 2&amp;gt;/dev/null &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'± '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return
    &lt;/span&gt;hg root &amp;gt;/dev/null 2&amp;gt;/dev/null &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'☿ '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Indicate that the CWD contains a python virtualenv (white snake symbol),&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# or that a virtualenv is active (yellow snake symbol)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;virtualenvCheck &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; -a bin/activate &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; -n &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$VIRTUAL_ENV&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; ; &lt;span class=&quot;k&quot;&gt;then
    if &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; -n &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$VIRTUAL_ENV&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; ; &lt;span class=&quot;k&quot;&gt;then
      &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$fg_bold&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[yellow]蛇 &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$reset_color&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else
      &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$fg&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;[white]蛇 &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$reset_color&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fi
  fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PROMPT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'%(!.%{$fg_bold[red]%}.%{$fg_bold[white]%})%n%{$reset_color%}@%{$fg_bold[white]%}%m%{$reset_color%} ➤  %(5L.%{$fg[red]%}.%(3L.%{$fg[yellow]%}.%{$fg[white]%}))LVL $SHLVL%{$reset_color%} $LINENUM %{$fg[white]%}%D{%a %b %d %Y}%{$reset_color%} ➤  %(2T.%{$fg_bold[red]%}.%(1T.%{$fg_bold[red]%}.%{$fg[white]%}))%T%{$reset_color%}
%(2j.%{$fg_bold[red]%}%j .%(1j.%{$fg_bold[yellow]%}%j .))%{$reset_color%}%~ %{$fg_bold[red]%}$(vcsCheck)%{$reset_color%}$(virtualenvCheck)%(?.%{$fg_bold[green]%}✓.%{$fg_bold[red]%}✗)%{$reset_color%} '&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This file looks pretty ugly, and unfortunately that tends to be true of most shell scripts. In particular, the syntax for PROMPT and RPROMPT is completely inscrutable to human beings. To make matters worse, search engines generally will not return relevent results if you make queries like “zsh %{“. Here are &lt;a href=&quot;http://www.bash2zsh.com/zsh_refcard/refcard.pdf&quot;&gt;two&lt;/a&gt; &lt;a href=&quot;http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html&quot;&gt;cheatsheets&lt;/a&gt; to help you decipher the prompt. Again, I adapted my prompt from &lt;a href=&quot;http://stevelosh.com/blog/2010/02/my-extravagant-zsh-prompt/&quot;&gt;Losh’s example&lt;/a&gt;, so I recommend reading his post if you’re confused by anything you see here. I’m only going to focus on the &lt;code class=&quot;highlighter-rouge&quot;&gt;precmd&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;virtualenvCheck&lt;/code&gt; functions.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;precmd&lt;/code&gt; is a special function in zsh.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; If defined, zsh will execute the function immediately before it draws the shell prompt. I use it to update the battery indicator and scale my prompt to different pane or terminal widths. I use &lt;code class=&quot;highlighter-rouge&quot;&gt;RPROMPT&lt;/code&gt; for the battery indicator only; everything else is part of &lt;code class=&quot;highlighter-rouge&quot;&gt;PROMPT&lt;/code&gt;. Therefore, in order to get the date and time to appear right-aligned in the pane, I change the length of the line of dashes with &lt;code class=&quot;highlighter-rouge&quot;&gt;precmd&lt;/code&gt;. To get the target length for the line, I use the &lt;code class=&quot;highlighter-rouge&quot;&gt;COLUMNS&lt;/code&gt; environment variable to get the width of the pane, subtract the number of characters that never change (such as the date and time), and then subtract the length of the hostname (which can change).&lt;/p&gt;

&lt;p&gt;Notice that I do not define &lt;code class=&quot;highlighter-rouge&quot;&gt;RPROMPT&lt;/code&gt; in the same way that Losh does. For some reason, his method did not work for me, so I had to modify his Python script to return the indicator and color separately. Here’s the new code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;table style=&quot;border-spacing: 0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot; style=&quot;text-align: right&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# coding=UTF-8&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;subprocess&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Popen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ioreg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-rc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;AppleSmartBattery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PIPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;communicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;o_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitlines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'MaxCapacity'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;o_cur&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitlines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'CurrentCapacity'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;o_chr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitlines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'IsCharging'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;b_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o_max&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rpartition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'='&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;b_cur&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o_cur&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rpartition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'='&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;b_chr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o_chr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rpartition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'='&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;charge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b_cur&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b_max&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;charge_threshold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;charge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Output&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;total_slots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slots&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;filled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;charge_threshold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_slots&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;u'▸'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_slots&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;u'▹'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'utf-8'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;color_green&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$fg_bold[green]&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;color_yellow&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$fg_bold[yellow]&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;color_red&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$fg_bold[red]&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;color_cyan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$fg_bold[cyan]&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;color_reset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$reset_color&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;color_out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;color_cyan&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b_chr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'Yes'&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color_green&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color_yellow&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color_red&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color_out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color_reset&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, let’s look at &lt;code class=&quot;highlighter-rouge&quot;&gt;virtualenvCheck&lt;/code&gt;. This function checks for two different conditions. First, if a Python virtualenv is currently active, it represents this fact with 蛇 (the Chinese character for “snake”) in yellow. Second, if the CWD contains an inactive virtualenv, the 蛇 character is white instead of yellow. The function itself is very easy to understand; it just checks for the presence of environment variables created by virtualenv. &lt;code class=&quot;highlighter-rouge&quot;&gt;precmd&lt;/code&gt; also checks for one of these environment variables to prevent virtualenv from modifying the prompt. By default, an active virtualenv will prepend the name of the directory in which it is contained. I decided to disable that behavior because it ruined the spacing of the prompt, and I am able to infer the location of the virtualenv from context.&lt;/p&gt;

&lt;p&gt;That’s pretty much everything to say about my zsh theme. The main lesson is to use shell functions to make the prompt dynamic and expressive. If you’re dead-set on bash, the same lesson applies, but unfortunately you miss out on &lt;code class=&quot;highlighter-rouge&quot;&gt;RPROMPT&lt;/code&gt;. Next up, we’ll look at how we can use functions to simplify common tasks and “overload” system binaries to change their behavior.&lt;/p&gt;

&lt;h2 id=&quot;whats-your-function&quot;&gt;What’s Your Function?&lt;/h2&gt;

&lt;p&gt;As I mentioned before, Oh My Zsh provides dozens of helpful plugins for &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins-Overview&quot;&gt;Django, Ruby, Node, Sublime, and many more tools&lt;/a&gt;. If you’ve already loaded some plugins in your .zshrc file, you can run &lt;code class=&quot;highlighter-rouge&quot;&gt;functions | less&lt;/code&gt; to see all available functions (but note that functions starting with underscores are not meant to be called by users directly).&lt;/p&gt;

&lt;p&gt;Sometimes, however, you just won’t be able to find the right tool for the job. No worries! As programmers, we’ll make our own solution. Just write a function in ~/.oh-my-zsh/custom/ARBITRARY-NAME.zsh, and zsh will pick it up automatically.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; Type the name of the function into the shell (no parentheses) and PRESTO! Let’s look at two examples:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;table style=&quot;border-spacing: 0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot; style=&quot;text-align: right&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Open the .gitignore in the current repository, or prompt the user to create&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# one if it does not already exist&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;gitignore&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  setopt local_options no_case_match
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GIT_CHECK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;git rev-parse --show-toplevel 2&amp;gt; /dev/null&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; ! &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; -n &lt;span class=&quot;nv&quot;&gt;$GIT_CHECK&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fg_bold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[red]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Error:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;reset_color&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; Directory is not a git repository&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;false
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else
    if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; -a &lt;span class=&quot;nv&quot;&gt;$GIT_CHECK&lt;/span&gt;/.gitignore &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;$EDITOR&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$GIT_CHECK&lt;/span&gt;/.gitignore
    &lt;span class=&quot;k&quot;&gt;else
      &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;tmp
      vared -p &lt;span class=&quot;s1&quot;&gt;'No .gitignore found. Create one? (y/n) '&lt;/span&gt; tmp
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$tmp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ &lt;span class=&quot;s2&quot;&gt;&quot;^(y|yes)$&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;.DS_Store&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*.swp&quot;&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&quot;nv&quot;&gt;$GIT_CHECK&lt;/span&gt;/.gitignore
      &lt;span class=&quot;k&quot;&gt;else
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false
      &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi
    fi
  fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Every time I start a new project, one of the first things I do is create a .gitignore file to prevent myself from checking in project dependencies, swap files, and application credentials. I occasionally need to make changes to this file, which entails navigating to the root directory of the application and typing &lt;code class=&quot;highlighter-rouge&quot;&gt;vim .gitignore&lt;/code&gt;. Not so bad, right? Maybe not, but we can do better. Currently, we can’t tab-complete the file until we’ve typed &lt;code class=&quot;highlighter-rouge&quot;&gt;vim .giti&lt;/code&gt;, because otherwise zsh doesn’t know if we mean .gitignore or the .git directory. Fix the completion issue, add in the ability to open or create the file from anywhere in the project directory, and we have a perfect use-case for a zsh function.&lt;/p&gt;

&lt;p&gt;If you understood the functions in the .zsh-theme file, this new example should be relatively easy to follow. A few notes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;setopt local_options no_case_match&lt;/code&gt; makes the regex match on line 17 case-insensitive.&lt;/li&gt;
  &lt;li&gt;I use local variables using the &lt;code class=&quot;highlighter-rouge&quot;&gt;local&lt;/code&gt; keyword in order to avoid polluting the environment unnecessarily.&lt;/li&gt;
  &lt;li&gt;The command &lt;code class=&quot;highlighter-rouge&quot;&gt;git rev-parse --show-toplevel&lt;/code&gt; returns the root of the git repository, assuming we are within one. Otherwise it throws an error that we pipe to /dev/null.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;vared&lt;/code&gt; prints the string following the &lt;code class=&quot;highlighter-rouge&quot;&gt;-p&lt;/code&gt; option, waits for user input, and stores the value in the variable given.&lt;/li&gt;
  &lt;li&gt;I assume that the user has specified the path to the binary of their favorite editor in the &lt;code class=&quot;highlighter-rouge&quot;&gt;EDITOR&lt;/code&gt; variable. We want to avoid hard-coding, of course!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While writing this post, I found out that Oh My Zsh already has its own &lt;code class=&quot;highlighter-rouge&quot;&gt;gitignore&lt;/code&gt; plugin. From what I can tell, it uses &lt;a href=&quot;https://www.gitignore.io/&quot;&gt;gitignore.io&lt;/a&gt; to generate language-specific .gitignore files. I haven’t used it, and I’ll probably just stick to my own solution, but it may be worth a look before you use my code.&lt;/p&gt;

&lt;p&gt;Our first example demonstrates how to use zsh functions to simplify basic actions and save time. The function we created had a name that didn’t conflict with any other executables in our PATH. Avoiding name conflicts is important because zsh actually tries to resolve command names with functions &lt;em&gt;first&lt;/em&gt;, before searching the PATH. So what happens if we make a function called &lt;code class=&quot;highlighter-rouge&quot;&gt;gcc&lt;/code&gt;? If done carelessly, the result will be the disruption of C program compilation. However, the ability to override executables also gives us a way to make transparent wrapper functions that augment default behavior. Let’s see one more example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;table style=&quot;border-spacing: 0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot; style=&quot;text-align: right&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Open multiple files in vim with vertical split&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;vim&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$# &lt;/span&gt;-ge 2 &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$EDITOR&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt; -O
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$EDITOR&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This function is obviously very simple, but its implications are vast. Every time I type the word &lt;code class=&quot;highlighter-rouge&quot;&gt;vim&lt;/code&gt; in my shell, this function is called instead of the real vim binary. It looks at the number of arguments provided to the function and decides how to invoke the binary depending on the result. If one argument is found, the function calls vim normally. Otherwise, it instructs vim to open the files in parallel vertical windows. Normally, vim handles multiple file arguments by opening one buffer at a time, starting with the first argument, and opening each subsequent buffer when the previous one is closed. I dislike the default behavior because I either provided the second filename by mistake (and I’d like to solve the problem immediately) or I actually did want to see both files at the same time (in which case I’d prefer the parallel window option to be the default).&lt;/p&gt;

&lt;p&gt;Again, notice that I’m using the &lt;code class=&quot;highlighter-rouge&quot;&gt;EDITOR&lt;/code&gt; variable as a stand-in for the full filepath to the vim binary. If you decide to override other executables using this pattern, you’ll need to hardcode the full paths or create your own environment variables. You cannot just use the original command name, as zsh will again perform a lookup in the list of functions first, causing an infinite loop.&lt;/p&gt;

&lt;p&gt;While the code examples above are all zsh scripts, similar programs may be written for bash. However, while Oh My Zsh provides a safe place to put custom scripts in ~/.oh-my-zsh/custom, bash users will have to make their own local scripts directory and prepend it to their PATH.&lt;/p&gt;

&lt;h2 id=&quot;from-a-to-zsh&quot;&gt;From A to Zsh&lt;/h2&gt;

&lt;p&gt;If you’re just beginning to learn the ways of shell fu, I hope I’ve convinced you to at least give zsh a try. Whether you’re building complex themes or autocompleting git commands, zsh is a blast to use. Personally, I’m most excited about executable overloading, and I plan on doing much more of it. Have any ideas for executables to extend with scripting? Think you can give a better example? Have the best prompt in town? I’d love to see what you come up with. Happy hacking!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Though, really, all shell scripting languages are pretty quirky. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;Bash provides an alternative called &lt;a href=&quot;http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x264.html&quot;&gt;PROMPT_COMMAND&lt;/a&gt;. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;If you plan on making something a little more robust, or you have multiple functions, consider creating a plugin. Put your work in ~/.oh-my-zsh/custom/plugins/YOUR-PLUGIN/YOUR-PLUGIN.plugin.zsh, and make sure to include the plugin in your .zshrc: &lt;code class=&quot;highlighter-rouge&quot;&gt;plugins=(..... YOUR-PLUGIN ....)&lt;/code&gt;. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
]]></description>
        <pubDate>Thu, 09 Apr 2015 00:00:00 +0000</pubDate>
        <link>http://blog.nodenexus.com/2015/04/09/extending-zsh-functionality/</link>
        <guid isPermaLink="true">http://blog.nodenexus.com/2015/04/09/extending-zsh-functionality/</guid>
      </item>
    
      <item>
        <title>A Shark on the Network</title>
        <description><![CDATA[&lt;p&gt;DISCLAIMER: I do not condone monitoring network traffic with intent to spy or otherwise cause harm to people. My interest in the techniques described below is academic. I write in the hope that I can improve Internet security, or at least increase public awareness of vulnerabilities. If you are attempting to replicate my work, please be careful to do it in a controlled setting, such as your own home. Despite &lt;a href=&quot;http://arstechnica.com/tech-policy/2012/09/sniffing-open-wifi-networks-is-not-wiretapping-judge-says/&quot;&gt;court rulings like this one&lt;/a&gt;, the legality of packet sniffing on public networks is very murky, and you may get in a lot of trouble.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I’ve spent a lot of time this year thinking about networking, the web, and security on the Internet. Since the Snowden leaks, revelations about the scale and sophistication of government cyberweapons have the public talking about the danger of metadatacollection. In response, I began to wonder how easy it would be for any would-be adversary to perform a practical collection attack on a standard WiFi network. In order to judge the difficulty for myself, I decided it was time to dabble in the Dark Arts.&lt;/p&gt;

&lt;h2 id=&quot;starting-to-sniff&quot;&gt;Starting to Sniff&lt;/h2&gt;

&lt;p&gt;Enter &lt;a href=&quot;https://www.wireshark.org/&quot;&gt;Wireshark&lt;/a&gt;, a popular “packet sniffer”. Wireshark records, or “captures”, the various messages sent and received by your computer’s network card. If you’ve taken a class on computer networking, you’ve probably already downloaded the program; if not, you should get it now (for free) if you want to follow along.&lt;/p&gt;

&lt;p&gt;Normally, Wireshark only captures the packets whose source or destination are your own computer. However, it can also be used to configure your network card to enter “promiscuous mode”, allowing you to capture all network traffic indiscriminately. The metaphorical equivalent is a mailbox that, instead of receiving letters addressed to a single house, receives a copy of every letter addressed to any house on the street. If you’re wondering why the network card has access to all messages on the network, consider that you &lt;em&gt;need&lt;/em&gt; to see every message in order to determine which ones you are supposed to receive.&lt;/p&gt;

&lt;p&gt;Entering promiscuous mode turns out to be remarkably easy; just go to ‘Capture Options’, double-click on the interface you want to capture on, and select the options to capture packets in promiscuous mode as well as monitor mode.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; I find it odd that entering promiscuous mode alone is not enough to perform the capture. Perhaps one of you can tell me why it works that way.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;div class=&quot;figure-wrap&quot;&gt;
  &lt;figure&gt;
    &lt;img src=&quot;/assets/img/wireshark1.png&quot; /&gt;
    &lt;figcaption&gt; 
      Directions for capturing on an interface in promiscuous mode.
    &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Your computer should now capture all packets observed at the interface, instead of only the packets going to or from your own machine. To confirm that you’re capturing all traffic on the network, type &lt;code class=&quot;highlighter-rouge&quot;&gt;http.host == xkcd.com&lt;/code&gt; into Wireshark’s filter bar and go to &lt;a href=&quot;http://xkcd.com&quot;&gt;xkcd.com&lt;/a&gt; from another device. If you capture the packets, you’re in business.&lt;/p&gt;

&lt;div class=&quot;figure-wrap&quot;&gt;
  &lt;figure&gt;
    &lt;img src=&quot;/assets/img/wireshark2.png&quot; /&gt;
    &lt;figcaption&gt; 
      The traffic destined for xkcd.com should look something like this.
    &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;You should take some time to play around with Wireshark and understand exactly how much power you now have. Just by clicking two checkboxes, you can observe every message sent to and from your local router; you can collect the IP and MAC addresses of all nearby hosts; you can map every request for a web page back to its source, know what was requested, and read all unencrypted data. All you did to access this information was instruct your machine not to throw away messages destined for other clients. You didn’t have to tamper with network hardware or other machines, you didn’t hurt network performance, and nobody can detect what you’re doing.&lt;/p&gt;

&lt;p&gt;The implications should concern you.&lt;/p&gt;

&lt;h2 id=&quot;look-ma-no-gui&quot;&gt;Look Ma, No GUI&lt;/h2&gt;

&lt;p&gt;Of course, Wireshark isn’t the easiest tool to use when it comes to actually analyzing the data you collect. You’ll still have to inspect packets manually in order to extract the information you’re looking for. What if you just want a list of all MAC address pairs which exchanged messages? Wouldn’t it be nice if you could programmatically collect, filter, and print only the packets or header fields you’re interested in?&lt;/p&gt;

&lt;p&gt;Assuming you downloaded Wireshark, You already have just the tool for the job, called Tshark. Tshark provides CLI (command line interface) support for most of the actions you can do in Wireshark, making it possible to integrate network sniffing into your programs. The only catch is that, depending on how you installed Wireshark, You may have to find the Tshark binary and add its location to your PATH in order to use it.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Let me demonstrate just how powerful Tshark can be. A few weeks ago at HackPrinceton, I presented a tool I called &lt;a href=&quot;http://challengepost.com/software/hostshark&quot;&gt;HostShark&lt;/a&gt;. HostShark sniffs the network for outgoing web traffic, both HTTP and HTTPS, and visualizes the hostnames of the traffic destinations using &lt;a href=&quot;http://d3js.org/&quot;&gt;D3&lt;/a&gt;. I used Tshark to capture packets, extract the necessary header fields, and pipe the data to a Python program for further processing. Incredibly, that entire series of operations was performed in a single line of bash:&lt;/p&gt;

&lt;pre class=&quot;terminal&quot;&gt;&lt;code&gt;$ tshark -lIY &quot;tcp.port==443 or http.request&quot; -T fields -E separator=&quot;|&quot; -e ip.dst -e http.host 2&amp;gt; /dev/null | python process.py&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I won’t explain what each of these command line options is for (&lt;code class=&quot;highlighter-rouge&quot;&gt;tshark help&lt;/code&gt; is your friend), but I’ll give you the gist. This command promiscuously captures outgoing HTTP and HTTPS packets. HTTP traffic may be filtered directly via &lt;code class=&quot;highlighter-rouge&quot;&gt;http.request&lt;/code&gt;, but HTTPS traffic is a little bit more complicated because Tshark and Wireshark don’t provide a built-in filter. However, we can create a de facto filter with &lt;code class=&quot;highlighter-rouge&quot;&gt;tcp.port==443&lt;/code&gt;, taking advantage of the convention for HTTPS traffic to use port 443. We now extract the destination IP and HTTP hostname from the packet, separating the values with a vertical line (‘|’). For example, a request to xkcd.com might result in the output “107.6.106.82|xkcd.com”. Note that HTTPS traffic will not have an HTTP hostname header, so the returned value will be the empty string. The extracted data is finally piped to the Python program below:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;table style=&quot;border-spacing: 0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot; style=&quot;text-align: right&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;json&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;socketIO_client&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SocketIO&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;urllib2&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;ips&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SocketIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'localhost'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7717&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socketIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;buff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;''&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;buff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buff&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endswith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'|'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ips&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                        &lt;span class=&quot;c&quot;&gt;# make the API call here&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urllib2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://stat.ripe.net/data/reverse-dns-ip/data.json?resource='&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'data'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'result'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;ips&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'data'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'result'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;socketIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'host'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'host'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'data'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'result'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;ips&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;lookup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ips&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookup&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;socketIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'host'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'host'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;stat.ripe.net&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;socketIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'host'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'host'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;buff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;''&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again, I won’t go into detail about how this program works (partly because it doesn’t matter, and partly because I’m not a Pythonista and don’t want to teach bad practices). It takes each incoming line, splits it at the ‘|’ and checks if the hostname is non-empty. If so, the hostname is forwarded to a server via &lt;a href=&quot;http://socket.io/&quot;&gt;Socket.io&lt;/a&gt;. Otherwise, the hostname must first be determined through a &lt;a href=&quot;http://en.wikipedia.org/wiki/Reverse_DNS_lookup&quot;&gt;reverse DNS lookup&lt;/a&gt; on the IP address. The &lt;code class=&quot;highlighter-rouge&quot;&gt;ips&lt;/code&gt; dictionary stores the results of the lookups to prevent duplicate requests to the lookup API.&lt;/p&gt;

&lt;h2 id=&quot;hostbusters&quot;&gt;Hostbusters&lt;/h2&gt;

&lt;p&gt;Now that I’ve revealed the gooey center of HostShark, let’s see it in action. I’m not going to bother with explaining the frontend or backend code here, since that isn’t the point of this blog post. You are, of course, encouraged to check out the rest of the code &lt;a href=&quot;https://github.com/kronion/HostShark&quot;&gt;on my GitHub&lt;/a&gt;, and pull requests are welcome.&lt;/p&gt;

&lt;p&gt;A few notes on how HostShark works. The visualizer refreshes every fifteen seconds and shows the hostnames of all requests made in the past minute. The hostnames are displayed heirarchically as a series of concentric arcs. The innermost arcs represent top-level domains (TLDs). Every subsequent arc is a subdomain of the one within.&lt;/p&gt;

&lt;p&gt;Here’s a screencast of HostShark in action:&lt;/p&gt;

&lt;div class=&quot;figure-wrap&quot;&gt;
  &lt;figure&gt;
    &lt;img src=&quot;/assets/img/hostshark.gif&quot; /&gt;
    &lt;figcaption&gt; 
      An example of a real capture at HackPrinceton.
    &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;h2 id=&quot;youre-gonna-need-a-bigger-boat&quot;&gt;You’re Gonna Need a Bigger Boat&lt;/h2&gt;

&lt;p&gt;When you eavesdrop on connections without interfering with them, you are performing what is known as a “passive” attack. HostShark is just one example of a passive attack. Other possible passive attacks include mapping all communicating pairs of hosts or simply analyzing the contents of HTTP packets.&lt;/p&gt;

&lt;p&gt;Passive attacks take advantage of three fundamental limitations of modern networking:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Network protocols leak metadata. HTTPS and SSL encryption may protect your data from prying eyes, but the encrypted payload must still be wrapped in TCP, IP, and ethernet headers in order to be transported to its destination. Those headers expose IP addresses, MAC addresses, and other transport details. The headers themselves cannot be encrypted because routers and switches must be able to read them in order to forward the traffic; this is an inherent limitation of the design of the Internet.&lt;/li&gt;
  &lt;li&gt;The destination of your traffic may reveal your intent. This is really a corollary to #1. Given that the source and destination of a message is public knowledge, the corresponding payload is only truly private if a third party cannot guess the contents with greater than negligable probabilty. In the case of requests made to well-known services on the Internet, it might be possible to make quite educated guesses about what is being exchanged. For example, if I know you’re sending messages to united.com, I can probably guess that you’re booking a trip. If you’re visiting WikiLeaks or freedom.press, I know you’re interested in political activism. The danger increases as websites use subdomains to divide services. If you watch the screencast above, you will see that Facebook uses different subdomains for their various frontend proxies. By analyzing the traffic, I might be able to determine that edge-star-shv-04-atl1.facebook.com is used to serve requests for images, while channel-proxy-shv-04-frc3.facebook.com handles comments or chat. Even if I can’t read the traffic, I have fine-grained knowledge of what you are doing.&lt;/li&gt;
  &lt;li&gt;Passive attacks are undetectable. As I said before, there is no change to any machine except your own, and nobody else’s network service is negatively impacted by your actions. As long as nobody is looking over your shoulder, you are completely invisible.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unfortunately, until a solution to these limitations is devised (and widely deployed!), there is no way to prevent passive attacks from occurring. You can only hope to mitigate the damage by exercising discretion on public Internet. For now, the sharks roam free.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;In this post, I describe a family of attacks based on passive observation of the traffic on the network. Passive attacks are not the end of the story, however. If an attacker is able to insert herself along the “path” between two hosts, becoming one of the computers to receive and forward the packets, she can perform an “active” attack by modifying packets mid-transit. Such an attacker is known as a man-in-the-middle (MitM). MitM are extremely dangerous because they may cause an end host to reveal information which would have otherwise remained secret. For instance, a MitM could change a webpage to transmit login credentials insecurely. The only disadvantage of an active attack over a passive attack is the possibility of being detected. Fortunately, Princeton detects (some) active attacks.&lt;/p&gt;

&lt;p&gt;I don’t have any plans to write about active attacks right now. I’m reluctant to teach such a powerful and harmful technique. That being said, the knowledge is out there for those who are willing to do a little digging.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Note that your computer may not come with a network card capable of promiscuous network monitoring. I have no problems on a 2013 Macbook, and I’d expect even older Macs to work as well. With PCs, it depends on the hardware vendor. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;Since It is possible that the behavior is dependent on the hardware or operating system. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;On Mac, I found the Tshark binary at &lt;code class=&quot;highlighter-rouge&quot;&gt;/Applications/Wireshark.app/Contents/Resources/bin/tshark&lt;/code&gt;. I added it to my PATH by making a softlink from my &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/local/bin&lt;/code&gt; directory to the location of the binary. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
]]></description>
        <pubDate>Fri, 28 Nov 2014 00:00:00 +0000</pubDate>
        <link>http://blog.nodenexus.com/2014/11/28/a-shark-on-the-network/</link>
        <guid isPermaLink="true">http://blog.nodenexus.com/2014/11/28/a-shark-on-the-network/</guid>
      </item>
    
  </channel>
</rss>
