<?xml version="1.0" encoding="utf-8"?>
	<feed xmlns="http://www.w3.org/2005/Atom">
	<title><![CDATA[grack.com]]></title>
	<link href="https://grack.com/atom.xml" rel="self"/>
	<link href="https://grack.com/"/>
	<icon>https://grack.com/resource/favicon/favicon-160x160.png</icon>
	<logo>https://grack.com/resource/favicon/favicon-160x160.png</logo>
	<updated>2022-12-21T09:19:38-07:00</updated>
	<id>https://grack.com/</id>
	<author>
		<name><![CDATA[Matt Mastracci]]></name>
		<email><![CDATA[matthew@mastracci.com]]></email>
	</author>
	<generator uri="http://jekyllrb.com/">Jekyll</generator>
	
	
	<entry>
		<title type="html"><![CDATA[Deriving a Bit-Twiddling Hack: Signed Integer Overflow]]></title>
		<link href="https://grack.com/blog/2022/12/20/deriving-a-bit-twiddling-hack"/>
		<updated>2022-12-20T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2022/12/20/deriving-a-bit-twiddling-hack</id>
		<content type="html"><![CDATA[<p><em>Thanks to <a href="https://mastodon.online/@raph/">Raph Levien</a> and <a href="https://github.com/electronicarts/EAStdC/blob/fbcc34e89c63636054334888f3a5bd7ac2fd4b76/include/EAStdC/EABitTricks.h#">Electronic Arts</a> for inspiring this post!</em></p>

<p>As a thin layer on top of assembly language, C’s integer arithmetic APIs have always been minimal, effectively just mapping the underlying assembly opcodes to the C arithmetic operators. In addition, while unsigned arithmetic can safely overflow in C, signed arithmetic overflow is considered undefined behaviour, and UB <a href="https://blog.tchatzigiannakis.com/undefined-behavior-can-literally-erase-your-hard-disk/">can end up in heartache for C developers</a>.</p>

<p>More modern languages like Rust have a much richer integer API, however. By default, using the standard addition and subtraction operators in debug mode, integer APIs will <code>panic!</code> on overflow or underflow. The same operators will wrap in two’s-complement mode in release mode, though the behaviour is considered defined. If the developer wants to specify <a href="https://doc.rust-lang.org/std/primitive.i32.html#method.carrying_add">carrying</a>, <a href="https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add">wrapping</a>, <a href="https://doc.rust-lang.org/std/primitive.i32.html#method.checked_add">checked</a>, or <a href="https://doc.rust-lang.org/std/primitive.i32.html#method.saturating_add">saturating</a> operations, APIs for each of these modes are available.</p>

<p>We don’t have these convenient APIs available <a href="https://gustedt.wordpress.com/2022/12/18/checked-integer-arithmetic-in-the-prospect-of-c23/">in C yet</a> (<a href="#epilogue">see the epilogue</a> for some nuance), but it would be great to have them. Given that signed arithmetic overflow is undefined behaviour, can we build a function with the following C signature that works?</p>

<pre><code>bool will_add_overflow(int32_t a, int32_t b);
</code></pre>

<p>All modern machines use <a href="https://en.wikipedia.org/wiki/Two%27s_complement">two’s complement</a> representation for negative integers, but C was developed <a href="https://en.wikipedia.org/wiki/Method_of_complements">when computing was experimenting with other forms of representing signed integers</a>. In this post, we will safely assume that all processors we’re targetting on are <em>not</em> using one of the alternative forms. If you find yourself programming for esoteric machines, you may wish to consult your local manual or guru.</p>

<p>A valid, quick-and-dirty solution to this would be to use <a href="https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules#:~:text=Integer%20Promotions,-Integer%20types%20smaller&amp;text=If%20all%20values%20of%20the,converted%20to%20an%20unsigned%20int%20.">integer promotion</a> and add 64-bit signed integers instead, checking to see if the result is within range of an <code>int16_t</code>:</p>

<pre><code>bool will_add_overflow_64bit(int32_t a, int32_t b) {
    // a and b are promoted to 64-bit signed integers
    int64_t result = (int64_t)a + b;
    if (result &lt; INT32_MIN || result &gt; INT32_MAX) {
        return true;
    }
    return false;
}
</code></pre>

<p>No undefined behaviour! It also has the advantage of being easily read and obviously correct. But this required sign-extending two 32-bit numbers and performing two 64-bit additions:</p>

<pre><code>will_add_overflow_64bit:
        movsxd  rax, edi
        movsxd  rcx, esi
        add     rcx, rax
        movsxd  rax, ecx
        cmp     rax, rcx
        setne   al
        ret
</code></pre>

<p>We can do better by taking advantage of the fact that on two’s-complement machines, addition is bitwise-identical between signed and unsigned numbers so long as you ignore carry, overflow, underflow and any other flags. In addition, the C specification (C99 6.3.1.3 ¶2) guarantees that the bit pattern will be preserved on a two’s-complement system.</p>

<p>We know that unsigned overflow is not UB, and we know that we can only overflow if a &gt; 0 and b &gt; 0, and we can only underflow if a &lt; 0 and b &lt; 0. If either a or b is zero, we’re safe. We also know that adding two positive integers must result in a positive result if no overflow occurred. For two negative integers, the result must also be negative. If we find that the sign of the sum does not match the sign expected, we’ve wrapped around!</p>

<pre><code>bool will_add_overflow_if(int32_t a, int32_t b) {
    // Explicitly convert to uint32_t and then back
    int32_t c = (int32_t)((uint32_t)a + (uint32_t)b);
    if (a &gt; 0 &amp;&amp; b &gt; 0 &amp;&amp; c &lt; 0) {
        return true;
    }
    if (a &lt; 0 &amp;&amp; b &lt; 0 &amp;&amp; c &gt;= 0) {
        return true;
    }
    return false;
}
</code></pre>

<p>And we get a fairly hefty assembly representation:</p>

<pre><code>will_add_overflow_if:
        lea     ecx, [rsi + rdi]
        test    edi, edi
        jle     .LBB2_3
        test    esi, esi
        jle     .LBB2_3
        mov     al, 1
        test    ecx, ecx
        jns     .LBB2_3
        ret
.LBB2_3:
        test    esi, edi
        sets    dl
        test    ecx, ecx
        setns   al
        and     al, dl
        ret
</code></pre>

<p>This is arguably a bit worse, as now we have a <a href="https://en.algorithmica.org/hpc/pipelining/branching/">branch in the mix</a>. But we can start to see a pattern here:</p>

<table style="border-collapse: collapse; text-align: center;" border="">
<tr>
<th>a</th>
<th>b</th>
<th>c</th>
<th>result</th>
</tr>
<tr>
<td>&gt; 0</td>
<td>&gt; 0</td>
<td>&lt; 0</td>
<td>true</td>
</tr>
<tr>
<td>&lt; 0</td>
<td>&lt; 0</td>
<td>&gt;= 0</td>
<td>true</td>
</tr>
</table>

<p>In two’s-complement, the expression <code>x &lt; 0</code> is equivalent to the expression <code>(x &amp; 0x80000000) == 0x80000000</code>. Similarly, <code>x &gt;= 0</code> is equivalent to <code>(x &amp; 0x80000000) == 0</code>.</p>

<p>Let’s create a <code>NEG</code> macro with the above expression and reproduce our pseudo-truth table in code. Note that we’ll also collapse the if statements into a single boolean expression so we can eliminate those branches:</p>

<pre><code>bool will_add_overflow_expression(int32_t a_, int32_t b_) {
    // Explicitly work with uint32_t in this function
    uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
    uint32_t c = (uint32_t)a + (uint32_t)b;
    #define NEG(x) (((uint32_t)(x) &amp; 0x80000000) == 0x80000000)
    return ((!NEG(a) &amp;&amp; !NEG(b) &amp;&amp; NEG(c)) 
        || (NEG(a) &amp;&amp; NEG(b) &amp;&amp; !NEG(c)));
    #undef NEG
}
</code></pre>

<p>This is looking better, but because we’re using <a href="https://en.wikipedia.org/wiki/Short-circuit_evaluation">short-circuiting logic</a>, those branches are still there: we still have a jump!</p>

<pre><code>will_add_overflow_expression:
        mov     eax, esi
        or      eax, edi
        setns   dl
        mov     ecx, esi
        add     ecx, edi
        sets    al
        and     al, dl
        test    edi, edi
        jns     .LBB3_3
        test    al, al
        jne     .LBB3_3
        test    esi, esi
        sets    dl
        test    ecx, ecx
        setns   al
        and     al, dl
.LBB3_3:
        ret
</code></pre>

<p>We can get rid of the branches by using non-short-circuiting bitwise operators:</p>

<pre><code>bool will_add_overflow_bitwise(int32_t a_, int32_t b_) {
    uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
    uint32_t c = (uint32_t)a + (uint32_t)b;
    #define NEG(x) (((uint32_t)(x) &amp; 0x80000000) == 0x80000000)
    return ((!NEG(a) &amp; !NEG(b) &amp; NEG(c)) 
        | (NEG(a) &amp; NEG(b) &amp; !NEG(c)));
    #undef NEG
}
</code></pre>

<p>And now it’s starting to look pretty compact (though we can do better):</p>

<pre><code>will_add_overflow_bitwise:
        lea     ecx, [rsi + rdi]
        mov     eax, esi
        or      eax, edi
        and     esi, edi
        xor     eax, esi
        not     eax
        and     eax, ecx
        xor     eax, esi
        shr     eax, 31
        ret
</code></pre>

<p>Notice that the assembly gives us a bit of a hint here that repeated use of our macro isn’t actually necessary. The sign bit we’re interested in isn’t tested until the end of the function! Because we’re testing the same bit in every part of the expression, and bits in a given position only interact with other bits in the same position, we can pull that bit test out of the whole expression:</p>

<pre><code>bool will_add_overflow_bitwise_2(int32_t a_, int32_t b_) {
    uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
    uint32_t c = (uint32_t)a + (uint32_t)b;
    #define NEG(x) (((uint32_t)(x) &amp; 0x80000000) == 0x80000000)
    return NEG((~a &amp; ~b &amp; c) | (a &amp; b &amp; ~c));
    #undef NEG
}
</code></pre>

<p>We can also make use of the knowledge that testing the sign bit is the same as an unsigned shift right:</p>

<pre><code>bool will_add_overflow_bitwise_3(int32_t a_, int32_t b_) {
    uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
    uint32_t c = (uint32_t)a + (uint32_t)b;
    return ((~a &amp; ~b &amp; c) | (a &amp; b &amp; ~c)) &gt;&gt; 31;
}
</code></pre>

<p>Not too bad! But let’s revisit the truth table and instead use the value of the sign bit directly. What we see is that <code>a</code> and <code>b</code> need to be the same value, and <code>c</code> needs to be the opposite value:</p>

<table style="border-collapse: collapse; text-align: center;" border="">
<tr>
<th>a</th>
<th>b</th>
<th>c</th>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>1</td>
</tr>
</table>

<p>This truth table shows that what we ultimately want to test is this:</p>

<pre><code>(a == 1 &amp;&amp; b == 1 &amp;&amp; c == 0) || (a == 0 &amp;&amp; b == 0 &amp;&amp; c == 1)
</code></pre>

<p>… but with a bit of work, we can simplify this down to two shorter expression candidates:</p>

<pre><code>(a == b) &amp;&amp; (a == !c)
(c == !a) &amp;&amp; (c == !b)
</code></pre>

<p>For bit twiddling like we’re doing here, xor (<code>^</code>) can work like a “not-equals” operator (outputs 1 iff the inputs are 0,1 or 1,0), which means we can re-write our two expressions like so:</p>

<pre><code>~(a ^ b) &amp; (c ^ a)
(c ^ a) &amp; (c ^ b)
</code></pre>

<p>By looking at those two options, is there a hint that one might be cheaper to implement? Let’s plug both into the compiler and see what we get!</p>

<pre><code>bool will_add_overflow_optimized_a(int32_t a_, int32_t b_) {
    uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
    uint32_t c = (uint32_t)a + (uint32_t)b;
    return (~(a ^ b) &amp; (c ^ a)) &gt;&gt; 31;
}

bool will_add_overflow_optimized_b(int32_t a_, int32_t b_) {
    uint32_t a = (uint32_t)a_, b = (uint32_t)b_;
    uint32_t c = (uint32_t)a + (uint32_t)b;
    return ((c ^ a) &amp; (c ^ b)) &gt;&gt; 31;
}
</code></pre>

<p>And the resulting compiled versions:</p>

<pre><code>will_add_overflow_optimized_a:
        lea     eax, [rsi + rdi]
        xor     eax, edi
        mov     ecx, edi
        xor     ecx, esi
        not     ecx
        and     eax, ecx
        shr     eax, 31
        ret
will_add_overflow_optimized_b:
        lea     eax, [rsi + rdi]
        xor     edi, eax
        xor     eax, esi
        and     eax, edi
        shr     eax, 31
        ret
</code></pre>

<p>We have a clear winner here: the compiler can do a much better job with <code>(c ^ a) &amp; (c ^ b)</code>. This is most likely because of the common sub-expression and the removal of the bitwise-not operator.</p>

<p>We can also confirm that there’s no known undefined behaviour by <a href="https://c.godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1AB9U8lJL6yAngGVG6AMKpaAVxYMQAZi%2BkHAGTwGTAA5dwAjTGIJAE5SAAdUBUJbBmc3D29fROSbAUDgsJZI6K44y0xrVKECJmICdPdPHwtMKzyGGrqCAtCIqNiLWvrGzJaFYZ6gvuKBsoBKC1RXYmR2DgBSACYvIOQ3LABqDa9HCfRw1BcAOgQT7A2NAEFt3YZ91yOTs4J8QVv7o8Xjs9gdMMdTudbACvA9nkDLi5DgB3Oi0YxMdDoYyoABuUSotFQyOMQQIxCCyWQEDJXi2xgIhyYpEOtPpjPC82OAHYAEJAw6C1mCOkMw7ETAKVy0AgnfnPIXizAEFYMQ6mcKuOg2BgYrE4/HEQnEiDMw7hFnbABsEqlMvmcqBG25ABEnc9EbQUWi9di8QSiSSrZJwoQaSL2UyWWyxZyefKnoqAPRJplMhjoc1MiWHeLEVAsVAETCZoiHYMAWlDjOSwGCmbJmGAUQUAqFZODYtt0sZJxdh3DBE7BHmTGOW155sdCvbVAH3ZlEMchwAkiEACqigCya55jmdy4Xvdhq4326eAA0uc6E4rFRKVcQ1eTXJhp4mhc63TPBQ/VYcqDEJR3y/d0nk9b1aHRTE/UNY0STwKhB1FRkzRjDlrz5NtBRTQ5sFUeJaDwZBCFoABPQ40AYQ1GTLLUIzFQxSwQRhzSYZAAGtsOFAgUMoiF%2B2Q9l5igejeOEsdtknCAxJQ%2BZOXfRVEIHSSTw0ccrWtLN7kOdTrS05Al10zDbzvX9lX/F83y8UzBVAn9WTnU0jL0rZNLc7TTl0jSDIhB4vH7DQTO4%2B8LKfQ4rMUz9XW4v9wsA2hgJsp0YvhD0ri9VEoN9A0A2JYxMAI21kgEITGOMaMGI5Yxgoc3D8MI4jSIo5ESA470CAQQ5ZMjIIIoQPAFAA1x3g6biesYgSBwmkcmAqzzBJm%2BTjCiwUZv4vtpvQ0dx2kpbwlW8cvCwGhgkOEJsAAcQgVQuSgGTtpu68PI0VQAA4NE%2Br6goEzbXo%2B77PodBy4rVKAwDAC7rqYZ73KtQ4IahiA430jykeQeZrwcxUDwPAckZhny0au5HYa0xGSYxzHDteEaTvOq6Uu/F50qRLLoP1f0jUDYxq1RJQytQ%2Bb0PNGr43GkXVMW7a5pZcIpoeqrlsO9bDM2xXxIZHapK2pWDuShzXhO6YGeu26B1Ex7za0/7AaB36At0967aC2KwrBiAKeh2GEchkmUeJ66qeObHouXCACZ9pGA/hr2ICph0DY/OydjpzA5yhpmwIg9mcq5%2BDecIfnMGMLZBaZYWqtF2rk%2B6yWFaW2WFt1zWR3CFak8VVWG5l3aW7k/XbKO42zqR837qWp6NKdgHAevAK/udu3gdr0HTagAA/SSPI3%2BWDMw8Pt/hved6pmnU4zdPTaztLwIyyCOdgvKST5waS68cum5F9ua67%2Bv1cbvNPejsNYDw7kPbuADe461AcJQebtHwey3tPXe08MZ7hUtPE%2B8MN7B0BCeLwXAQKpRZnfNmPoYK5W5vlVA8QbAsDwAALxLBiT%2BldW7V3Fg5daUt%2B4SSAT3PW4CJZVzViAxufdYFa3gSDd2A4N7OQ2AAVmwOaH28djgqKZJjPyOlCHEOZgie%2BudKH5x5rQ%2BhTCWHhDYZVDhP8uG1x4YI1uo4BFQKESrEWYjpZK23ntbaMjV5yKgGrLRhMtIaOUaozk89/KqP0UneypCySHBYEwIIEBcSoDwOgX%2B7Yq7FgmMYUQShWxKP5Eo/sm0bwhSFBoUgdSU68i4I00OgoKytKaaeTc9ItyXjabXRUa5enGH6ReQ4FZDhdPaT07ca5BlmUFCM%2BZIQ%2B4zNrqBJJhsdgj3BOubAQh1zUBMo5AcSEzRxghptNAxAJTWFOXmMkSFthbAAGIZK9K8o6c5XkgHHEozM2xAXKMcAwV5LJLmJ0nF%2BHkhiHL8GIAOVJeApoaDlKyIyyRmGoCQkUggJSmBlK5KmbFmBcUQHxYSspyjeToqqdC1kUkpL5LMoi5FghDjaDRRi7l3xDhkopVS0pkoSUCqsUKyUBKRXlLpcol0jLtDMonKypZgp/6O2FUSyUtK8DysOmq7%2BU0tU0oqUqqpBqlkQVufc48/YTGczgjzMkFIGBUlNHLaF3TFQHKORAB1T9qFBhDIQL1syfWHOOQGqhBdEJhqGUs31UaKGOufgVIqkoSoMHjWqiNfro1mPyq/JQObc2CiTf6lNgaC7FpLlsUtZaK0FqdUWoub9jBeAbbmptVaY3mLoXgBhzDsQw0tWZHt2VTEtpJBYwdVjsQKU7ks5JOMSHJI4IsWgnAlG8E8BwLQpBUCcGXAoZYqxwSvB4KQAgmgN2LA4t4bk1wuDcitFsDQbluRKO5F%2Bq0cQt0cEkLu29h7OC8AUCABpN790btIHAWASA0AsHiHQKI5BKBIZQ/QaIyB9iGGAFwJRn1SBYFxMRTAAA1PAmBkQAHl4iME4FemgMoWyUHCCB0MzBiBkSY7wJDbBBC0YYOREDWB0lGHEDBkjeBbV4HxBB6ThVKiuGLHx8ggg2ggaIuEYgdQyLOCwCB8kg6%2BOLEJEwYACgqM0fo4x7gvB%2BCCBEGIdgUgZCCEUCodQ0ndCtIMEYEApgSn6DwOECDkBFizoEIpistGvCTKoAoQwKRmF9lrPWCsjZmzEArIW5E5BkNERIgQCsI0Msliy5pnLFYXzvCYB0QrjUSsVgq%2BgKrxYat1dEI1wdzXCAdabFEVreA6wVmQAgfDmBwNtEqB0ewGZRieFaQEaYRQSggCUQkJIKQBBLb0DkXbDBejrbmK0do1RJj7daRUKoAguj1BO/0aIW2JjdGu0MboT3ZilEWKelYawJCbu3cB6TR6OCHHelaCswZKIBeANMpR1wNDI4HLgQgJAjpcHmLwaDWhMakAfVsGI1xJAxA0JIK0XgYjk7euTmIb19CcCA6QPdB7wfgcg9e29ix4OIBAMp5AqmSDodNMQKzyhDBtCEAgYke6r2YboA11Ikvgi0Bl3LkDivsMoDw0YQjxHtdRFo6pjXyI2e8EF08cXinLeqEqDUP4YGPPCFEOIdzTn5BKDUCBvz%2Bh8NBbMKF8L8AosDpi5wOLCWKxJZSzYNLAU2uDZq/lprxWBvldG5l7Lw3uvK4EGnpqpWk859y3n3rRWi/J%2BGxl8bk2jDTaWADtzQw/iq%2Bl7L836nySYHWFe5Een4hmaZxwHdrOQPg/wipogSKocw8kHD/DiPkeo4gI4Fk6OZ9Y5x9zmDBOH0%2BGuD4Y/J/T8j5Zxb0DHBOdQZ58DjgWxQfs%2Bd3ju9pBDRZpAJIIAA%3D%3D%3D">compiling it with clang’s <code>-fsanitize=undefined</code> feature</a>. No UB warnings are printed, which means no UB was detected!</p>

<h2 id="epilogue">Epilogue</h2>

<p>While this is the fastest we can get with bog-standard C99, this isn’t necessarily the best we can do.</p>

<p>Rust makes use of the compiler intrinsics to access the overflow flag of the processor directly:</p>

<pre><code>pub fn add(a: i32, b: i32) -&gt; bool {
    a.checked_add(b).is_none()
}

example::add:
        add     edi, esi
        seto    al
        ret
</code></pre>

<p>It turns out that <a href="https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html">both GCC and LLVM have C intrinsics</a> that you can use. While they are non-portable to some compilers, they drastically simplify the assembly output!</p>

<pre><code>bool will_add_overflow_intrinsic(int32_t a, int32_t b) {
    int32_t result;
    return __builtin_add_overflow(a, b, &amp;result);
}
</code></pre>

<p>And, just like with the Rust compiler above, this generates optimal assembly!</p>

<pre><code>will_add_overflow_intrinsic:
        add     edi, esi
        seto    al
        ret
</code></pre>

<p>Not to worry about this being so deeply compiler-specific for now, however. This will be standardized in C23 with the <a href="https://gustedt.wordpress.com/2022/12/18/checked-integer-arithmetic-in-the-prospect-of-c23/">addition of the functions in the <code>stdckdint.h</code> header</a>.</p>

<p>A full suite of tests to explore the solutions <a href="https://c.godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1AB9U8lJL6yAngGVG6AMKpaAVxYMQAZi%2BkHAGTwGTAA5dwAjTGIJAE5SAAdUBUJbBmc3D29fROSbAUDgsJZI6K44y0xrVKECJmICdPdPHwtMKzyGGrqCAtCIqNiLWvrGzJaFYZ6gvuKBsoBKC1RXYmR2DgBSACYvIOQ3LABqDa9HCfRw1BcAOgQT7A2NAEFt3YZ91yOTs4J8QVv7o8Xjs9gdMMdTudbACvA9nkDLi5DgB3Oi0YxMdDoYyoABuUSotFQyOMQQIxCCyWQEDJXi2xgIhyYpEOtPpjPC82OAHYAEJAw6C1mCOkMw7ETAKVy0AgnfnPIXizAEFYMQ6mcKuOg2BgYrE4/HEQnEiDMw7hFnbABsEqlMvmcqBG25ABEnc9EbQUWi9di8QSiSSrZJwoQaSL2UyWWyxZyefKnoqAPRJplMhjoc1MiWHeLEVAsVAETCZoiHYMAWlDjOSwGCmbJmGAUQUAqFZODYtt0sZJxdh3DBE7BHmTGOW155sdCvbVAH3ZlEMchwAkiEACqigCya55jmdy4Xvdhq4326eAA0uc6E4rFRKVcQ1eTXJhp4mhc63TPBQ/VYcqDEJR3y/d0nk9b1aHRTE/UNY0STwKhB1FRkzRjDlrz5NtBRTQ5sFUeJaDwZBCFoABPQ40AYQ1GTLLUIzFQxSwQRhzSYZAAGtsOFAgUMoiF%2B2Q9l5igejeOEsdtknCAxJQ%2BZOXfRVEIHSSTw0ccrWtLN7kOdTrS05Al10zDbzvX9lX/F83y8UzBVAn9WTnU0jL0rZNLc7TTl0jSDIhB4vH7DQTO4%2B8LKfQ4rMUz9XW4v9wsA2hgJsp0YvhD0ri9VEoN9A0A2JYxMAI21kgEITGOMaMGI5Yxgoc3D8MI4jSIo5ESA470CAQQ5ZMjIIIoQPAFAA1x3g6biesYgSBwmkcmAqzzBJm%2BTjCiwUZv4vtpvQ0dx2kpbwlW8cvCwGhgkOEJsAAcQgVQuSgGTtpu68PI0VQAA4NE%2Br6goEzbXo%2B77PodBy4rVKAwDAC7rqYZ73KtQ4IahiA430jykeQeZrwcxUDwPAckZhny0au5HYa0xGSYxzHDteEaTvOq6Uu/F50qRLLoP1f0jUDYxq1RJQytQ%2Bb0PNGr43GkXVMW7a5pZcIpoeqrlsO9bDM2xXxIZHapK2pWDuShzXhO6YGeu26B1Ex7za0/7AaB36At0967aC2KwrBiAKeh2GEchkmUeJ66qeObHouXCACZ9pGA/hr2ICph0DY/OydjpzA5yhpmwIg9mcq5%2BDecIfnMGMLZBaZYWqtF2rk%2B6yWFaW2WFt1zWR3CFak8VVWG5l3aW7k/XbKO42zqR837qWp6NKdgHAevAK/udu3gdr0HTagAA/SSPI3%2BWDMw8Pt/hved6pmnU4zdPTaztLwIyyCOdgvKST5waS68cum5F9ua67%2Bv1cbvNPejsNYDw7kPbuADe461AcJQebtHwey3tPXe08MZ7hUtPE%2B8MN7B0BCeLwXAQKpRZnfNmPoYK5W5vlVA8QbAsDwAALxLBiT%2BldW7V3Fg5daUt%2B4SSAT3PW4CJZVzViAxufdYFa3gSDd2A4N7OQ2AAVmwOaH28djgqKZJjPyOlCHEOZgie%2BudKH5x5rQ%2BhTCWHhDYZVDhP8uG1x4YI1uo4BFQKESrEWYjpZK23ntbaMjV5yKgGrLRhMtIaOUaozk89/KqP0UneypCySHBYEwIIEBcSoDwOgX%2B7Yq7FgmMYUQShWxKP5Eo/sm0bwhSFBoUgdSU68i4I00OgoKytKaaeTc9ItyXjabXRUa5enGH6ReQ4FZDhdPaT07ca5BlmUFCM%2BZIQ%2B4zNrqBJJhsdgj3BOubAQh1zUBMo5AcSEzRxghptNAxAJTWFOXmMkSFthbAAGIZK9K8o6c5XkgHHEozM2xAXKMcAwV5LJLmJ0nF%2BHkhiHL8GIAOVJeApoaDlKyIyyRmGoCQkUggJSmBlK5KmbFmBcUQHxYSspyjeToqqdC1kUkpL5LMoi5FghDjaDRRi7l3xDhkopVS0pkoSUCqsUKyUBKRXlLpcol0jLtDMonKypZgp/6O2FUSyUtK8DysOmq7%2BU0tU0oqUqqpBqlkQVufc48/YTGczgjzMkFIGBUlNHLaF3TFQHKORAB1T9qFBhDIQL1syfWHOOQGqhBdEJhqGUs31UaKGOufgVIqkoSoMHjWqiNfro1mPyq/JQObc2CiTf6lNgaC7FpLlsUtZaK0FqdUWoub9jBeAbbmptVaY3mLoXgBhzDsQw0tWZHt2VTEtpJBYwdVjsQKU7ks5JOMSHJI4IsWgnAlG8E8BwLQpBUCcGXAoZYqxwSvB4KQAgmgN2LA4t4bk1wuDcitFsDQbluRKO5F%2Bq0cQt0cEkLu29h7OC8AUCABpN790btIHAWASA0AsHiHQKI5BKBIZQ/QaIyB9iGGAFwJRn1SBYFxMRTAAA1PAmBkQAHl4iME4FemgMoWyUHCCB0MzBiBkSY7wJDbBBC0YYOREDWB0lGHEDBkjeBbV4HxBB6ThVKiuGLHx8ggg2ggaIuEYgdQyLOCwCB8kg6%2BOLEJEwYACgqM0fo4x7gvB%2BCCBEGIdgUgZCCEUCodQ0ndCtIMEYEApgSn6DwOECDkBFizoEIpistGvCTKoAoQwKRmF9lrPWCsjZmzEArIW5E5BkNERIgQCsI0Msliy5pnLFYXzvCYB0QrjUSsVgq%2BgKrxYat1dEI1wdzXCAdabFEVreA6wVmQAgfDmBwNtEqB0ewGZRieFaQEaYRQSggCUQkJIKQBBLb0DkXbDBejrbmK0do1RJj7daRUKoAguj1BO/0aIW2JjdGu0MboT3ZilEWKelYawJCbu3cB6TR6OCHHelaCswZKIBeANMpR1wNDI4HLgQgJAjpcHmLwaDWhMakAfVsGI1xJAxA0JIK0XgYjk7euTmIb19CcCA6QPdB7wfgcg9e29ix4OIBAMp5AqmSDodNMQKzyhDBtCEAgYke6r2YboA11Ikvgi0Bl3LkDivsMoDw0YQjxHtdRFo6pjXyI2e8EF08cXinLeqEqDUP4YGPPCFEOIdzTn5BKDUCBvz%2Bh8NBbMKF8L8AosDpi5wOLCWKxJZSzYNLAU2uDZq/lprxWBvldG5l7Lw3uvK4EGnpqpWk859y3n3rRWi/J%2BGxl8bk2jDTaWADtzQw/iq%2Bl7L836nySYHWFe5Een4hmaZxwHdrOQPg/wipogSKocw8kHD/DiPkeo4gI4Fk6OZ9Y5x9zmDBOH0%2BGuD4Y/J/T8j5Zxb0DHBOdQZ58DjgWxQfs%2Bd3ju9pBDRZpAJIIAA%3D%3D%3D">is available on Godbolt</a> or <a href="https://gist.github.com/mmastrac/4c00b7790c8a13e13d1baca08b1b9cd6">as a Gist</a>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Painting myself into a corner while bootstrapping a language]]></title>
		<link href="https://grack.com/blog/2022/12/16/painting-myself-in-a-bootstrapping-corner"/>
		<updated>2022-12-16T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2022/12/16/painting-myself-in-a-bootstrapping-corner</id>
		<content type="html"><![CDATA[<p>I was hoping to make more progress on self-hosting my scripting language (<a href="https://github.com/mmastrac/kalos">Kalos</a>) this week, but I’m running out of steam because I think I coded myself into a corner. This is not a post where I’ve got everything figured out, but instead I’m taking a few moments to re-hash where things are at and figure out a plan for the future.</p>

<p>My original plan for this language was to offer a Python-like experience with minimal resource requirements: it should be able to run on an AVR, on bare metal, or even as part of a DOS executable. I had originally planned to support compilation on those devices, and even built a <a href="https://github.com/mmastrac/kalos/blob/289d15ec84f6da01961e9c1eb6951f9f8c88586c/src/kalos_parse.c">zero-allocation parser</a>. The runtime is lightweight, integers are a configurable size, and strings are even optional. I believe it’ll be a great option on lower-end devices where Python is just too heavy.</p>

<p>Over the last week I started work to extract a small piece of the parser that deals with KIDL (example of KIDLE below), the part of the language that glues it to your C code. This is currently part of the existing parser, and the only piece that I could think of to carve off on the slow march to true self-hosting.</p>

<pre><code>idl {
    prefix "kalos_module_idl_";
    dispatch name;

    module builtin {
        fn println(s: string) = kalos_idl_compiler_println;
        fn print(s: string) = kalos_idl_compiler_print;
        fn log(s: string) = kalos_idl_compiler_log;
    }
...
</code></pre>

<p>Where I’m stuck now is that the language is <em>almost</em> good enough to parse itself, but I’m finding lots of corner cases and papercut bugs that make it less-than-ideal. For example, I’m finding that the parser as-is is not <a href="https://github.com/mmastrac/kalos/blob/289d15ec84f6da01961e9c1eb6951f9f8c88586c/src/compiler/compiler_idl_out.kalos#LL47C5-L47C9">quite good enough to handle function calls that are deeply nested in expressions</a>.</p>

<p>I also ended up hacking in some <a href="https://github.com/mmastrac/kalos/blob/289d15ec84f6da01961e9c1eb6951f9f8c88586c/src/compiler/compiler_idl_object.kalos">dynamic-dispatch objects</a> that help with not having classes, but that’s not a long-term thing that I want to support in lieu of a proper object/class system.</p>

<p>Eventually I’ll have to commit to rewriting the whole parser in Kalos, but as the title of the post suggests, I’m stuck in a <em>potential energy well</em> where the next steps are going to be difficult. The current parser is written in C and – while the code is pretty clean – it’s a lot of work to make changes to it. It’s going to take some time and effort to add support for things like classes, tear-off functions, etc, and being allocation-free doesn’t make any of this easy.</p>

<p>My mistake was being too ambitious and going right for C as the bootstrap, rather than something higher level. I should have started with Python as the bootstrap!</p>

<p>So I need to gather enough energy to choose and work on one of the following paths:</p>

<ol>
  <li>Commit to rewriting the parser in Kalos, maybe after adding support for hashtables/dicts to the language. The language spec is still small enough that I could port the current parser. Debugging is very difficult, and you need to ensure that you’re running the code while developing it to discover if you’ve accidentally stepped on one of the many landmines. Once I have the parser/compiler in a higher-level language like Kalos itself, these landmines will be much easier to fix!</li>
  <li>Rewrite the parser in Python, knowing that I’ll have to rewrite it in Kalos later. This might not be terrible because the language is supposed to be python-like and there might be a mechanical translation route available. The thought of writing more code to throw away doesn’t fill me with a lot of joy, but it might just be what I have to do.</li>
  <li>Scrap the hand-rolled parser and switch to something like <a href="https://sqlite.org/src/doc/trunk/doc/lemon.html">Lemon</a>. We’re already using the amazing <a href="https://re2c.org/">re2c</a> to write the lexer, so adding another tool isn’t a bad idea. Again, we’re putting in a bunch of effort knowing that this will be tossed away later, but maybe there’s a middle ground like just having Lemon build an AST, then have Kalos script generate the bytecode?</li>
</ol>

]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Hacking Bluetooth to Brew Coffee from GitHub Actions: Part 3 - GitHub Actions]]></title>
		<link href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3"/>
		<updated>2022-12-04T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3</id>
		<content type="html"><![CDATA[<p>This is the last part of a three-part series covering the odyssey of getting a new coffeemaker, learning BTLE and how it works, reverse-engineering the Bluetooth interface and Android applications for the coffeemaker, writing a <a href="https://github.com/mmastrac/longshot">Rust-based CLI interface</a>, and finally, hooking it all up to a GitHub actions bot that lets you <a href="https://github.com/mmastrac/brew-a-coffee-demo/">brew a coffee just by filing an issue</a>!</p>

<ul>
  <li><a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1">Part 1: Introduction</a></li>
  <li><a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2">Part 2: Reverse Engineering</a></li>
  <li>
<a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3">Part 3: GitHub Actions</a>
    <ul>
      <li><a href="#getting-started">Getting Started</a></li>
      <li><a href="#extracting-the-command-line">Extracting the Command-Line</a></li>
      <li><a href="#building-the-workflow">Building the Workflow</a></li>
    </ul>
  </li>
</ul>

<p>In <a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2">part 2</a> we got the command-line application working, and now it’s time to connect the dots and build a secure, yet web-accessible interface.</p>

<p>We could choose a standard web host, add some sort of authentication on top of it, build the right web tooling to integrate with the nice command-line application we built, and all the associated security so random people can’t brew coffee. But as you’ve guessed from the title of these posts, we’re going hook this command-line app into a private GitHub repo as our “interface”.</p>

<p>Making use of GitHub issues for automating weird things isn’t new, but I think this is the first time you can make coffee from it!</p>

<h2 id="getting-started">Getting Started</h2>

<p>Here’s our goal:</p>

<ol>
  <li>We want to allow users to brew a coffee from a GitHub issue, which will be pre-populated from a number of pre-defined templates</li>
  <li>The issue will contain part of the command-line that we want to run, and we’ll need to validate that it’s reasonable and correct, and that nobody is trying to inject any sort of “funny business” to break/backdoor the runner</li>
  <li>We don’t want coffee brewers to have to chase down the status of the brewing operation, so we’re going to make use of issue comments as our basic UI.  The user will be able to follow the progress of their coffee inside of the issue, and get a notification when it’s done.</li>
</ol>

<p>This is what the user will see just before they brew the coffee:</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-3-brew-template.png"><img src="https://grack.com/_thumbs/c3aa2149543857c4484cd80af5928687-600-600"></a></p>

<p>The first question you might have is how we’re going to talk to a Bluetooth coffeemaker from GitHub’s system. This part turns out to be pretty easy: we can use <a href="https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners">GitHub self-hosted runners</a> as a backdoor into the coffeemaker’s physical location! By running this on a computing device that has a Bluetooth radio in proximity to the coffeemaker, we can send commands to it in response to events occurring in a repo. Conveniently the Raspberry Pi 3 Model B and Pi 4<a href="https://www.digikey.com/en/maker/blogs/raspberry-pi-wi-fi-bluetooth-setup-how-to-configure-your-pi-4-model-b-3-model-b"> both support Bluetooth</a>, but in our case we’re going to be using a spare MacBook that’s kicking around.</p>

<p>First thing, we need to create a new runner on GitHub for our project, and then set up the runner on the MacBook:</p>

<pre><code>curl -O -L https://github.com/actions/runner/releases/download/${version}/actions-runner-osx-x64-${version}.tar.gz
tar xzf ./actions-runner-osx-x64-${version}.tar.gz
./config.sh --url https://github.com/mmastrac/brew-a-coffee --token ${token}
./run.sh
</code></pre>

<p>GitHub actions are pretty flexible and we have a <a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows">huge number of events</a> that can trigger them. In our case, we want the creation of a new issue to trigger a run, so our trigger becomes:</p>

<pre><code>on:
issues:
    types: [opened]
</code></pre>

<p>We’ll pull in the <code>create-or-update-comment</code> action from <code>peter-evans</code> for updating the user about the status of their coffee:</p>

<pre><code>steps:
  - name: Add comment
    uses: peter-evans/create-or-update-comment@v2
</code></pre>

<p>And once the coffee is brewed or the process has failed for some other reason, we’ll want to close that issue, so we’re going to pull in <code>peter-evans/close-issue</code> for this:</p>

<pre><code>  - name: Close issue
    if: always()
    uses: peter-evans/close-issue@v2
</code></pre>

<p>The actual brewing part will be pretty easy as well, but it’s going to require use to fetch the text of the issue and use that to create the command-line to run.</p>

<p>Let’s take a look at the event information that GitHub provides to us in <code>$GITHUB_EVENT_PATH</code>. There’s a lot that GitHub provides for us in this file, and this particular one is trimmed down significantly:</p>

<pre><code>{
    "action": "opened",
    "issue": {
        ...
        "body": "This is my issue body comment\r\n",
        ...
        "title": "This is my issue title!",
        ...
    }
    ...
</code></pre>

<p><code>jq</code> is one the best tools for integrating JSON APIs with shell scripts, so we’ll make use of that. We’ll create a small test JSON file called <code>test.json</code> that contains just the interesting subset of what’s available in the file at <code>$GITHUB_EVENT_PATH</code>:</p>

<pre><code>{
    "action": "opened",
    "issue": {
        "body": "This is my issue body comment\r\n",
        "title": "This is my issue title!"
    }
}
</code></pre>

<p>First, we can test extraction of the issue body:</p>

<pre><code>$ jq -r '.issue.body' &lt; test.json
This is my issue body comment

$
</code></pre>

<p>That worked, but we’ve got some extra whitespace there. We can trim that with another <code>jq</code> command, <code>gsub</code>. By replacing leading or trailing whitespace (<code>gsub("^\\s+|\\s+$";"")</code>) with nothing, we can get just the text of the comment:</p>

<pre><code>$ jq -r '.issue.body|gsub("^\\s+|\\s+$";"")' &lt; test.json
This is my issue body comment
$
</code></pre>

<p>Better!</p>

<h2 id="extracting-the-command-line">Extracting the Command-Line</h2>

<p>Now what we want to do is allow the user to specify the command-line in the issue, but ensure that they can’t run anything nefarious on the runner. We developed a command-line cappuccino recipe in part 2 that we ran like this:</p>

<pre><code>cargo run -- brew --beverage cappuccino --coffee 40 --milk 100 --taste extrastrong
</code></pre>

<p>So let’s extract out everything past the hyphens and make that the required input in our newly-filed issues:</p>

<pre><code>brew --beverage cappuccino --coffee 40 --milk 100 --taste extrastrong
</code></pre>

<p>To work on extraction, we’ll update the <code>issue.body</code> field in our <code>test.json</code> file to this partial command-line:</p>

<pre><code>{
    "action": "opened",
    "issue": {
        "body": "brew --beverage cappuccino --coffee 40 --milk 100 --taste extrastrong\r\n"
    }
}
</code></pre>

<p>Since we are creating a valid partial command-line for our brewing app, we can make use of that fact that we know the exact structure. In this case, we know we want it to:</p>

<ol>
  <li>Start with the subcommand <code>brew</code>
</li>
  <li>Next, contain the beverage to brew with <code>--beverage &lt;something&gt;</code>
</li>
  <li>Finally, contain a list of beverage parameters which are limited to <code>coffee</code>, <code>milk</code>, <code>hotwater</code>, <code>taste</code>, and <code>temperature</code>. Each parameter is separated from its value by a space (ie: <code>--coffee 100</code>), and is either a number or an enumeration value (ie: <code>--taste strong</code>).</li>
</ol>

<p>We can then build a regular expression that will be limited to just the arguments we’re allowing here. We’ll use the <code>\w</code> character class as it’s a close match to the values required by our parameters.</p>

<p>We could go further in validating the <code>--beverage</code> parameter, or the values for the ingredients, but we know that those are carefully checked in the application and we’ll let the application handle the validation:</p>

<pre><code>^brew --beverage \w+( --(coffee|milk|taste|hotwater|temperature) \w+)*$
</code></pre>

<p>Now we can put it all together and extract the command-line like so (note that we have to escape the <code>\w</code> patterns in regular expression):</p>

<pre><code>CMDLINE=$(jq -r '.issue.body|gsub("^\\s+|\\s+$";"")|select(test("^brew --beverage \\w+( --(coffee|milk|taste|hotwater|temperature) \\w+)*$"))' &lt; $GITHUB_EVENT_PATH)
</code></pre>

<p>And that’s probably the only tricky part of the process. Now we can build our GitHub action, piece-by-piece.</p>

<h2 id="building-the-workflow">Building the Workflow</h2>

<p>First, the preamble that tells GitHub where and when to run the action, and what permissions it has:</p>

<pre><code>name: Brew

on:
  issues:
    types: [opened]

jobs:
  build:
    runs-on: self-hosted
    permissions:
      issues: write

steps:
</code></pre>

<p>Our first step will drop a comment into the issue so the user knows things are happening</p>

<pre><code>      - name: Add initial comment
        uses: peter-evans/create-or-update-comment@v2
        id: comment
        with:
          issue-number: $
          body: ' - [X] Getting ready to brew your ☕️!'
</code></pre>

<p>We’ll then install the <code>longshot</code> executable from <code>cargo</code> and let them know it was done:</p>

<pre><code>      - name: Install longshot
        run: cargo install --root /tmp/longshot -- longshot 
      - name: Update comment
        uses: peter-evans/create-or-update-comment@v2
        with:
          issue-number: $
          comment-id: $
          body: ' - [X] Installed the `longshot` executable'
</code></pre>

<p>Next, we’ll process the requested brew operation using the <code>jq</code> incantation from earlier. This step will create a <code>body.md</code> that we’ll use to update the comment, as well as <code>cmdline.txt</code> that will be used to execute our brewing operation later on:</p>

<pre><code>      - name: Process the request
        run: |
          OUTFILE=body.md
          CMDLINE=$(
            jq -r '
              .issue.body |
              gsub("^\\s+|\\s+$";"") |
              select(
                test("^brew --beverage \\w+( --(coffee|milk|taste|hotwater|temperature) \\w+)*$")
              )' &lt; $GITHUB_EVENT_PATH
          )
          echo Command-line we parsed was: $CMDLINE
          if [[ "$CMDLINE" == "" ]]; then
            echo " - [X] Couldn't parse the command line from your comment? 🤔" &gt; $OUTFILE
            exit 1
          fi
          echo -n ' - [X]' Running brew command: \`$CMDLINE\` &gt; $OUTFILE
          echo ' [(Log here)](https://github.com/'${GITHUB_REPOSITORY}'/actions/runs/'${GITHUB_RUN_ID}')' &gt;&gt; $OUTFILE
          echo "/tmp/longshot/bin/longshot $CMDLINE --device-name $" &gt; cmdline.txt
</code></pre>

<p>We then update the comment with <code>body.md</code>:</p>

<pre><code>      - name: Update comment
        uses: peter-evans/create-or-update-comment@v2
        with:
          issue-number: $
          comment-id: $
          body-file: body.md
</code></pre>

<p>And run the brewing command:</p>

<pre><code>      - name: Brew coffee
        run: |
          echo '&lt;details&gt;&lt;summary&gt;Log&lt;/summary&gt;&lt;pre&gt;' &gt; log.md
          sh -c "`cat cmdline.txt`" | tee -a log.md
          echo '&lt;/pre&gt;&lt;/details&gt;' &gt;&gt; log.md
          echo '✅ Success!' &gt;&gt; log.md
      - name: Update comment on success
        uses: peter-evans/create-or-update-comment@v2
        with:
          issue-number: $
          comment-id: $
          body-file: log.md
</code></pre>

<p>Finally, we’ll log a message to the comment on an error, and close the issue unconditionally:</p>

<pre><code>      - name: Update comment on failure
        if: failure()
        uses: peter-evans/create-or-update-comment@v2
        with:
          issue-number: $
          comment-id: $
          body: |
            &lt;br&gt;
            ❌ Failed! Please check the log for the reason.
      - name: Close issue
        if: always()
        uses: peter-evans/close-issue@v2
</code></pre>

<p>And with all those steps, we can get ourselves a coffee from GitHub!</p>

<p><video src="https://grack.com/assets/2022/12/part-3-brewing-github.mp4" autoplay="" controls=""></video></p>
<!-- <a class='image standard' href='https://grack.com/assets/2022/12/part-3-brew-template-complete.png'><img src='https://grack.com/_thumbs/e8c03c545a36144f86f5bb7bec39f9ef-600-600' /></a> -->

<p>While you can’t access my private repository that I’m using to brew us coffee at home, you can definitely try out the example repo that I’ve set up here which uses the command-line interface’s simulator and runs on GitHub’s action runners instead:</p>

<p><a href="https://github.com/mmastrac/brew-a-coffee-demo">https://github.com/mmastrac/brew-a-coffee-demo</a></p>

<p>To recap, we:</p>

<ul>
  <li><a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1">Figured out how to talk to the coffeemaker over Bluetooth and sniffed some packets</a></li>
  <li><a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2">Reverse engineered the application, figured out how to construct packets, and implemented a command-line applications</a></li>
  <li>And finally, <a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3">hooked the entire system up to GitHub actions!</a>
</li>
</ul>

<p><strong><em><a href="https://hachyderm.io/@mmastrac">Follow me on Mastadon</a> for more updates on this adventure!</em></strong></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Hacking Bluetooth to Brew Coffee from GitHub Actions: Part 2 - Reverse Engineering]]></title>
		<link href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2"/>
		<updated>2022-12-02T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2</id>
		<content type="html"><![CDATA[<p>This is part 2 of a three-part series covering the odyssey of getting a new coffeemaker, learning BTLE and how it works, reverse-engineering the Bluetooth interface and Android applications for the coffeemaker, writing a <a href="https://github.com/mmastrac/longshot">Rust-based CLI interface</a>, and finally, hooking it all up to a GitHub actions bot that lets you <a href="https://github.com/mmastrac/brew-a-coffee-demo/">brew a coffee just by filing an issue</a>!</p>

<ul>
  <li><a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1">Part 1: Introduction</a></li>
  <li>
<a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2">Part 2: Reverse Engineering</a>
    <ul>
      <li><a href="#understanding-the-packets">Understanding the Packets</a></li>
      <li><a href="#disassembling-the-delonghi-apk">Disassembling the Delonghi APK</a></li>
      <li><a href="#revisiting-the-brew-command">Revisiting the Brew Command</a></li>
      <li><a href="#further-reading-for-this-post">Further Reading</a></li>
    </ul>
  </li>
  <li><a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3">Part 3: GitHub Actions</a></li>
</ul>

<p>In <a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1">part 1</a> we got our coffeemaker brewing using a sniffed command that we logged from the actual application, and then sent to the coffeemaker using a small Rust program. However, we don’t really understand the language we’re speaking yet, we’re just repeating the application-to-device babbling we’ve snooped.</p>

<h2 id="understanding-the-packets">Understanding the Packets</h2>

<p>Now that we know that we can send a request, we want to understand what the format of the request looks like. The first thing we want to do is understand what a packet is. A packet is a chunk of data of a defined length, in contrast to a <em>stream</em> of data that continues indefinitely. Packets are used throughout most communication technologies and are a fundamental way of describing discrete communication messages.</p>

<p>When dealing with embedded devices, packets will almost always have a header, and sometimes a footer. The header and footer are called the <a href="https://en.wikipedia.org/wiki/Ethernet_frame">framing</a> of the packet, and they delimit it so we can identify exactly where it starts and stop.</p>

<p>Inside the header and footer might be things like <em>start-of-packet</em>, or <em>end-of-packet</em> markers, and a length for framing. There may also be additional metadata like a <a href="https://en.wikipedia.org/wiki/Checksum">checksum</a> to detect corruption.</p>

<p>Why is this framing important? Devices will often use framing to help recover from corruption. If you lose or corrupt a byte anywhere in the packet, you can often recover synchronization quickly by just restarting the packet parsing at the next byte that looks like a start byte.</p>

<p>Here’s a few packets we captured being sent from the coffeemaker to the application while asking it to brew a coffee, and then waiting for it to finish cleaning:</p>

<pre><code>0d0575f0c4d5                             # Some sort of status request
0d1483f007010100410900be02030c001c0206dc # Brew a cappuccino
0d0883f00702062f41                       # Cancel brewing

d00783f0010064d9                         # Response to brew/stop request
d012750f02040100400700000000000000d621   # Status response
d012750f04050100400c030900000000001cf0   # Status response
d012750f000000000000036400000000009080   # Status response
</code></pre>

<p>What information can we glean from this? First of all, the first byte is always <code>0d</code> or <code>d0</code> (13 or 240 in decimal), suggesting this is a start-of-packet byte that varies depending on the direction of communication. That’s one byte probably identified!</p>

<pre><code>+&gt; 0d 0575f0c4d5
+&gt; 0d 1483f007010100410900be02030c001c0206dc
+&gt; 0d 0883f00702062f41
|
+&gt; d0 0783f0010064d9
+&gt; d0 12750f02040100400700000000000000d621
+&gt; d0 12750f04050100400c030900000000001cf0
+&gt; d0 12750f000000000000036400000000009080
|
+--------------------------------------- Start of packet (0x0d or 0xd0)
</code></pre>

<p>Next, the second byte of the packet seems to vary depending on the length of the packet, and it corresponds exactly with the change in packet size. This is highly likely to be a length, and from what we can see here in a couple of the packets we captured earlier, it would be the length of the packet not including the start-of-packet byte.</p>

<pre><code>   v---5 bytes--v
0d 05 75 f0 c4 d5
   v------7 bytes-----v
d0 07 83 f0 01 00 64 d9
   v------------------18 bytes (0x12)------------------v
d0 12 75 0f 02 04 01 00 40 07 00 00 00 00 00 00 00 d6 21
^  ^
|  +------------------------------------------------------ Length of packet
+--------------------------------------------------------- Start of packet (0xd0)
</code></pre>

<p>We can’t glean much about the rest of the packet yet, but we’re getting some of the framing nailed down here. Time to pull out some more analysis tools.</p>

<p>There are three approaches we can use to understand the binary language of Delonghi’s ECAM machines:</p>

<ol>
  <li>We can disassemble the firmware of the coffeemaker and understand what it expects and what it sends, or</li>
  <li>We can observe the application’s communication with the coffeemaker over a period of time, changing one or two things at a time and seeing what changes in the protocol, or</li>
  <li>We can disassemble the application that controls the coffeemaker and understand its inputs and outputs.</li>
</ol>

<p>The firmware of the machine itself would be the ideal place for us to look, but according to some various coffeemaker-hacking forums, the controllers are <a href="https://en.wikipedia.org/wiki/PIC_microcontrollers">PIC</a>-based, and <a href="https://www.rapid7.com/blog/post/2019/04/30/extracting-firmware-from-microcontrollers-onboard-flash-memory-part-3-microchip-pic-microcontrollers/">disassembling/dumping PIC firmware somewhat tricky</a>.</p>

<p>In addition, a disadvantage to disassembling microcontroller firmware is that due to size constraints, it’s far less likely for text strings to have survived the compilation process to give us hints as to what’s going on. Finding leftover snippets of logging or “debug” print statements are gold for the reverse engineer, and we’d like to use that as a signpost to guide our future work.</p>

<p>Observing the application’s communication directly is definitely an option. This is inconvenient as we saw from the HCI snooping adventures earlier on, and we might not know how to perturb the system enough to fully understand most of the fields we receive.</p>

<p>The best option we’re left with is disassembling the application itself and looking for hints as to what it’s doing, hopefully for some symbols that give us names, or text strings that may give us context.</p>

<h2 id="disassembling-the-delonghi-apk">Disassembling the Delonghi APK</h2>

<p>We’re going to disassemble the Delonghi APK to learn more about how we can automate our caffeine fix.</p>

<p>Android applications are shipped in APK <em>(Android Package Kit)</em> format, and we’re going to download a few historical versions of the APK from <a href="https://m.apkpure.com/de-longhi-coffee-link/it.delonghi/versions">APK Pure</a>, a site that archives older versions of shipped applications. Getting a few different versions is a good idea, as developers will sometimes forget to enable <a href="https://developer.android.com/studio/build/shrink-code">obfuscation</a> in some versions. If we’re lucky enough to get a version of the application without obfuscation, we can get the internal names for constants and fields.</p>

<p>In the past, APK decompilation was somewhat tricky. As Android is Java-based, but doesn’t use Java’s bytecode directly, either you’d need to learn how to understand <a href="https://github.com/JesusFreke/smali">smali</a>, or you’d use <a href="https://github.com/pxb1988/dex2jar">dex2jar</a> to convert the app to a faux-Java JAR file and use standard Java analysis tools to reverse engineer it. <a href="https://github.com/skylot/jadx">Jadx</a> is a new Java analysis tool, which is far easier to use and much more powerful than the older tools.</p>

<p>Let’s open the APK in Jadx. Once it has decompiled that app, the first thing we’ll notice is that there are package names here. This is great news and suggests that even if the application is obfuscated, it’s not obfuscated fully and we’ll be able to learn how it ticks.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-disassembly-a.jpeg"><img src="https://grack.com/_thumbs/347e3da3eeb8d35e88f8fc9b50613687-600-600"></a></p>

<p>When we dig into some of the classes, we see method and field names, showing us a pretty clear representation of the original source code. Even better news!</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-disassembly-b.jpeg"><img src="https://grack.com/_thumbs/f85f2f6cab61b49d6ae930475bb7c603-600-600"></a></p>

<p>After decompiling, our first goal should be to conclusively identify the framing of the packets and answer the questions we raised earlier on. With some reading through the source, we can identify the source of one of the packets we saw being sent to the machine…</p>

<pre><code>0d 05 75 f0 c4 d5
</code></pre>

<p>… as coming from here:</p>

<pre><code>public static byte[] getByteMonitorMode(int i) {  
    String str = TAG;  
    DLog.m188e(str, "getByteMonitorMode  dataN" + i);  
    byte[] bArr = new byte[6];  
    bArr[0] = 0xd;                            // ** 0d
    bArr[1] = 5;                              // ** 05
    if (i == 0) {  
        bArr[2] = DATA_0_ANSWER_ID;  
    } else if (i == 1) {  
        bArr[2] = DATA_1_ANSWER_ID;  
    } else if (i == 2) {  
        bArr[2] = 117;                        // ** 75
    }  
    bArr[3] = 0xf0;                           // ** f0
    int checksum = checksum(bArr);  
    bArr[4] = (byte) ((checksum &gt;&gt; 8) &amp; 255); // ** c4 
    bArr[5] = (byte) (checksum &amp; 255);        // ** d5
    return bArr;  
}
</code></pre>

<p>We can see the canonical source for every byte in that packet above in this function. <code>0d</code> is the <em>start_of_packet</em> header. <code>05</code> is the length, and it looks like it’s just hardcoded here since the packet is always the same length. We can also see that the last few digits are a checksum, and if we dig into the <code>checksum</code> function, how it is calculated:</p>

<pre><code>public static int checksum(byte[] bArr) {  
    int i = 7439;  
    for (int i2 = 0; i2 &lt; bArr.length - 2; i2++) {  
        int i3 = (((i &lt;&lt; 8) | (i &gt;&gt;&gt; 8)) &amp; 65535) ^ (bArr[i2] &amp; 255);  
        int i4 = i3 ^ ((i3 &amp; 255) &gt;&gt; 4);  
        int i5 = i4 ^ ((i4 &lt;&lt; 12) &amp; 65535);  
        i = i5 ^ (((i5 &amp; 255) &lt;&lt; 5) &amp; 65535);  
    }  
    return i &amp; 65535;  
}
</code></pre>

<p>Great! <code>checksum</code> looks like it could be one of the <a href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">CRC family of functions</a>, but we don’t necessarily have to fully understand it yet if we have its implementation. We now have all the framing necessary to construct any packet:</p>

<pre><code>d0 LE (data) C1 C2
^  ^         ^--^-- Our checksum bytes   
+  +--------------- Length of packet, minus start-of-packet
+------------------ Start of packet (0xd0 or 0x0d depending on direction)
</code></pre>

<p>Now we can start to guess at the meaning of the rest of the bytes. Byte 2 appears to be a command ID. Byte 3 is a constant, and scanning the rest of the file suggests that it’s always <code>0x0f</code> or <code>0xf0</code>, depending on the command. That leaves the remainder of the packet for the command payload, if it’s used for the command.</p>

<pre><code>0d 05 75 f0 c4 d5
^  ^  ^  ^  ^--^-- Our checksum
|  |  |  +-------- Always 0xf0 or 0x0f
|  |  +----------- The command ID (0x75 = monitor mode 2)
|  +-------------- The packet length
+----------------- Start of packet (0x0d)
</code></pre>

<p>Since we have a single spot for calculating the packet checksum, and we know that every request requires a checksum to be calculated, we can figure out all the places in the app that create request packets to get a better idea of what we can ask the machine to do by looking for the callers of <code>checksum</code>:</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-find-usages.jpeg"><img src="https://grack.com/_thumbs/de03305db76e7912ab5bb889e8e467a5-600-600"></a></p>

<p>This is very interesting! There’s a lot of commands here, and each of them has a reasonably-well-defined name that we can use to understand what its function might be. We’ll have to start working through them one-by-one. With a bit of work, we can assemble a table of these commands:</p>

<pre><code>enum EcamRequestId {
    SetBtMode = 17,
    MonitorV0 = 96,
    MonitorV1 = 112,
    MonitorV2 = 117,
    BeverageDispensingMode = 131,
    AppControl = 132,
    ParameterRead = 149,
    ParameterWrite = 144,
    ParameterReadExt = 161,
    StatisticsRead = 162,
    Checksum = 163,
    ProfileNameRead = 164,
    ProfileNameWrite = 165,
    RecipeQuantityRead = 166,
    RecipePriorityRead = 168,
    ProfileSelection = 169,
    RecipeNameRead = 170,
    RecipeNameWrite = 171,
    SetFavoriteBeverages = 173,
    RecipeMinMaxSync = 176,
    PinSet = 177,
    BeanSystemSelect = 185,
    BeanSystemRead = 186,
    BeanSystemWrite = 187,
    PinRead = 210,
    SetTime = 226,
}
</code></pre>

<p>Some of these request IDs are guesses based on the surrounding code context, and some of them are defined in enumerations in the application source. It’s a pretty good start for us to get going on figuring out how to brew our own beverage from scratch.</p>

<h2 id="revisiting-the-brew-command">Revisiting the brew command</h2>

<p>From just the bytes sent across the connection it’s difficult to understand exactly how the application is creating the packet to brew a coffee. However, in the disassembly we find a function <code>dispenseBeveragePacket</code> that appears to construct the packet we saw before:</p>

<pre><code>if (arrayList != null) {  
    Iterator&lt;ParameterModel&gt; it3 = arrayList.iterator();  
    loop1: while (true) {  
        i4 = 0;  
        while (it3.hasNext()) {  
            next = it3.next();  
            if (next.getId() &lt; 23 || next.getId() == 28) {  
                if (bool.booleanValue() || i != 200 || next.getId() != 2) {  
                    i6 = i6 + 2 + i4;  
                    bArr[i6 + 6] = (byte) next.getId();  
                    if (Utils.isTwoBytesShort(next.getId())) {  
                        bArr[i6 + 7] = (byte) (next.getDefValue() &gt;&gt; 8);  
                        bArr[i6 + 8] = (byte) next.getDefValue();  
                        i4 = 1;  
                    }  
                }  
            }  
        }  
        bArr[i6 + 7] = (byte) next.getDefValue();  
    }  
    i5 = i4;  
}
</code></pre>

<p>If we clean it up a bit to some Java pseudocode, it looks like this:</p>

<pre><code>int index = 6;
for (ParameterModel param in params) {
    if (param.getId() &lt; CLEAN_TYPE || param.getId() == ACCESSORIO) {
        array[index++] = param.getId();
        if (Utils.isTwoBytesShort(param.getId())) {
            array[index++] = param.getDefValue() &gt;&gt; 8;   // upper 8 bytes
            array[index++] = param.getDefValue() &amp; 0xff; // 
        } else {
            array[index++] = param.getDefValue() &amp; 0xff;
        }
    }
}
</code></pre>

<p>So, from this pseudocode we see that a beverage is constructed from a list of ingredients (which with some further investigation, we find in the disassembled source as <code>IngredientsId</code> below), and an associated one or two byte value (<code>param.getDefValue()</code> above). Digging through the source for which ingredients are one or two bytes doesn’t yield much fruit, but maybe we can understand what’s going on by investigating further.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-disassembly-c.jpeg"><img src="https://grack.com/_thumbs/0e4bed862ff878b99a3b2b48b4247bed-600-600"></a></p>

<p>Where do we go next? We find that there are two commands that, based on their name, seem to be related to the application UI used for brewing: <code>RecipeQuantityRead</code> and <code>RecipeMinMaxSync</code>.</p>

<p>Let’s try sending these commands to the machine! To do this, it’s time to re-visit our Rust code.</p>

<p>First, let’s create a function that will add the packet framing (header, length and checksum) to any payload we want to send:</p>

<pre><code>pub fn checksum(buffer: &amp;[u8]) -&gt; [u8; 2] {
    let mut i: u16 = 7439;
    for x in buffer {
        let i3 = ((i &lt;&lt; 8) | (i &gt;&gt; 8)) ^ (*x as u16);
        let i4 = i3 ^ ((i3 &amp; 255) &gt;&gt; 4);
        let i5 = i4 ^ (i4 &lt;&lt; 12);
        i = i5 ^ ((i5 &amp; 255) &lt;&lt; 5);
    }

    [(i &gt;&gt; 8) as u8, (i &amp; 0xff) as u8]
}

fn packetize(buffer: &amp;[u8]) -&gt; Vec&lt;u8&gt; {
    let mut out = [&amp;[
        0x0d,
        (buffer.len() + 3).try_into().expect("Packet too large"),
    ], buffer].concat();
    out.extend_from_slice(&amp;checksum(&amp;out));
    out
}

async fn run_with_peripheral(peripheral: Peripheral, characteristic: Characteristic) -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {
    let data = packetize(/* data */);
    peripheral.write(&amp;characteristic, data, WriteType::WithoutResponse);
    Ok(())
}
</code></pre>

<p>Now we can start sending some example packets and exploring the responses. Here’s two test packet’s we’ll send (in pseudo-code and byte form):</p>

<pre><code>Packet                             Bytes
RecipeInfo(profile=1, beverage=7)  0d 07 a6f0 01 07 75c2
RecipeMinMaxInfo(beverage=7)       0d 06 b0f0 07 6af4
</code></pre>

<p>Let’s look at what comes back, in raw byte form (some spaces added to help the reader visualize the packet):</p>

<pre><code>RecipeInfo(profile=1, beverage=7):       
d0 17 a6f0 01 07 
↳ 0100410900be02030c001b0419011c02
↳ a2cd

RecipeMinMaxInfo(beverage=7):
d0 2c b0f0 07
↳ 010014004100b409003c00be038402000305
↳ 18010101190101010c0000001c000200
↳ 1b000404
↳ d03c
</code></pre>

<p>The first part of the response packets appear to be the machine echoing back the input. This makes sense, as the application will need a way to match up responses to requests.</p>

<p>For the remainder of the packet, we have the advantage of the decompilation above. We know the list of ingredients from the <code>IngredientsId</code> enumeration in the decompiled source, and if we match up the type of beverages with the ingredients, it makes a lot of sense that it’s what we’re seeing here:</p>

<pre><code>RecipeInfo response:

01·0041•09·00be•02·03•0c·00•1b·04•19·01•1c·02
---+--- ---+--- --+-- --+-- --+-- --+-- --+--  
   |       |      |     |     |     |     ╰---- Accessorio=2
   |       |      |     |     |     |          
   |       |      |     |     |     ╰---------- Visible=1
   |       |      |     |     |                
   |       |      |     |     ╰---------------- IndexLength=4
   |       |      |     |                      
   |       |      |     ╰---------------------- Inversion=0
   |       |      |                            
   |       |      ╰---------------------------- Taste=3
   |       |                                   
   |       ╰----------------------------------- Milk=190
   |                                           
   ╰------------------------------------------- Coffee=65

RecipeMinMaxInfo response:

01·0014·0041·00b4•09·003c·00be·0384•02·00·03·05•
--------+-------- --------+-------- -----+-----  
        |                 |              ╰------- Taste: 0&lt;=3&lt;=5
        |                 |                      
        |                 ╰---------------------- Milk: 60&lt;=190&lt;=900
        |                                        
        ╰---------------------------------------- Coffee: 20&lt;=65&lt;=180
&gt; 18·01·01·01•19·01·01·01•0c·00·00·00•1c·00·02·00•
  -----+----- -----+----- -----+----- -----+-----  
       |           |           |           ╰------- Accessorio: 0&lt;=2&lt;=0
       |           |           |                   
       |           |           ╰------------------- Inversion: 0&lt;=0&lt;=0
       |           |                               
       |           ╰------------------------------- Visible: 1&lt;=1&lt;=1
       |                                           
       ╰------------------------------------------- Programmable: 1&lt;=1&lt;=1
&gt; 1b·00·04·04
  -----+-----  
       ╰------- IndexLength: 0&lt;=4&lt;=4
</code></pre>

<p>From reading the application source, these packets seem to represent the current settings for the beverage, and the minimum and maximum ranges for each of the parameters. We can also start to guess at what the lengths of each of the ingredients’ parameter values are: most are a single byte, but a handful seem to be reliably two bytes wide and they all seem to deal with liquids.</p>

<p>Let’s confirm our intuition here by looking at the recipes for a latte and hot water:</p>

<pre><code>Latte recipe:

01·003c•09·01f4•02·03•0c·00•1b·04•19·01•1c·02
---+--- ---+--- --+-- --+-- --+-- --+-- --+--  
   |       |      |     |     |     |     ╰---- Accessorio=2
   |       |      |     |     |     |          
   |       |      |     |     |     ╰---------- Visible=1
   |       |      |     |     |                
   |       |      |     |     ╰---------------- IndexLength=4
   |       |      |     |                      
   |       |      |     ╰---------------------- Inversion=0
   |       |      |                            
   |       |      ╰---------------------------- Taste=3
   |       |                                   
   |       ╰----------------------------------- Milk=500
   |                                           
   ╰------------------------------------------- Coffee=60

Hot water recipe:

0f·00fa•19·01•1c·01
---+--- --+-- --+--  
   |      |     ╰---- Accessorio=1
   |      |          
   |      ╰---------- Visible=1
   |                 
   ╰----------------- HotWater=250
</code></pre>

<p>We can see that the pattern continues here: liquid amounts are two bytes long, while everything else is a single byte.</p>

<p>If you’re curious about every recipe this machine can make, <a href="https://gist.github.com/mmastrac/67b821666bdae50af4691b744432f801">a gist is available with a dump of the recipes</a>.</p>

<p>We can now put all the pieces together and build our own brewing command with a recipe that we’re going to write from scratch: a large cappuccino!</p>

<pre><code>83 f0 07 01 01 00 78 09 01 77 02 04 02
^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^- Preparation mode = PREPARE
|  |  |  |  |  |  |  |  |  |  +--+---- Taste (02) = strong (value 4)
|  |  |  |  |  |  |  +--+--+---------- Milk (09) = 375
|  |  |  |  +--+--+------------------- Coffee (01) = 120
|  |  |  +---------------------------- Trigger=START
|  |  +------------------------------- Beverage=Cappuccino (value 7)
|  +---------------------------------- Always 0xf0
+------------------------------------- Beverage dispense request   
</code></pre>

<p>Let’s send that to the machine and see what happens:</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-2-cappuccino-custom.jpg"><img src="https://grack.com/_thumbs/9c6160b55b185117386e8f6b4d2cdf3e-600-600"></a></p>

<p>Success! We have the most complicated and important part of communication with a coffeemaker working: brewing the coffee.</p>

<p>There’s a bit of work required to turn this into a full application, but you can find that pre-written in my <a href="https://github.com/mmastrac/longshot">longshot project on GitHub</a>. You don’t need to have this coffeemaker, as it includes a simulator mode that will allow you to brew a virtual coffee and test out the packet parsing and generation code.</p>

<p><video src="https://grack.com/assets/2022/12/part-2-coffee.mp4" autoplay="" controls=""></video></p>

<p><a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3"><em>Continue reading…</em></a> In <a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3">part three</a> of the series we’ll hook this up to GitHub Actions so that we can automate coffee brewing from the browser!</p>

<h2 id="further-reading-for-this-post">Further reading for this post</h2>

<ul>
  <li><a href="https://gist.github.com/mmastrac/67b821666bdae50af4691b744432f801">Dump of all recipes available on the Delonghi Dinamica Plus</a></li>
  <li><a href="https://www.rapid7.com/blog/post/2019/04/30/extracting-firmware-from-microcontrollers-onboard-flash-memory-part-3-microchip-pic-microcontrollers/">Extracting Firmware from Microcontrollers’ Onboard Flash Memory, Part 3: Microchip PIC Microcontrollers</a></li>
  <li><a href="https://braincoke.fr/blog/2021/03/android-reverse-engineering-for-beginners-decompiling-and-patching/">Android reverse engineering for beginners - Decompiling and patching</a></li>
  <li><a href="https://reverseengineering.stackexchange.com/questions/1523/what-techniques-are-used-in-reverse-engineering-a-serial-protocol">What techniques are used in reverse engineering a serial protocol?</a></li>
</ul>

<p><strong><em><a href="https://hachyderm.io/@mmastrac">Follow me on Mastadon</a> for more updates on this adventure!</em></strong></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Hacking Bluetooth to Brew Coffee from GitHub Actions: Part 1 - Bluetooth Investigation]]></title>
		<link href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1"/>
		<updated>2022-12-01T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1</id>
		<content type="html"><![CDATA[<p>This is going to be a long journey in three parts that covers the odyssey of getting a new coffeemaker, learning BTLE and how it works, reverse-engineering the Bluetooth interface and Android applications for the coffeemaker, writing a <a href="https://github.com/mmastrac/longshot">Rust-based CLI interface</a>, and finally, hooking it all up to a GitHub actions bot that lets you <a href="https://github.com/mmastrac/brew-a-coffee-demo/">brew a coffee just by filing an issue</a>!</p>

<ul>
  <li>
<a href="https://grack.com/blog/2022/12/01/hacking-bluetooth-to-brew-coffee-on-github-actions-part-1">Part 1: Bluetooth Investigation</a>
    <ul>
      <li><a href="#introduction">Introduction</a></li>
      <li><a href="#btle-background-and-traffic-sniffing">BTLE Background and Traffic Sniffing</a></li>
      <li><a href="#communicating-in-rust">Communicating in Rust</a></li>
      <li><a href="#further-reading-for-this-post">Further Reading</a></li>
    </ul>
  </li>
  <li><a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2">Part 2: Reverse Engineering</a></li>
  <li><a href="https://grack.com/blog/2022/12/04/hacking-bluetooth-to-brew-coffee-on-github-actions-part-3">Part 3: GitHub Actions</a></li>
</ul>

<h2 id="introduction">Introduction</h2>

<p>I’ve always been pretty content with using whatever coffeemaker I had nearby. For the last two or three years I’ve been using an old 2-in-1 Breville YouBrew coffeemaker, with a grinder built-in. It was a workhorse and worked perfectly until this September. A few months ago the machine asked me to run the regular descaling process to deal with our hard water, and this is where our adventure starts.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-breville-youbrew.jpeg"><img src="https://grack.com/_thumbs/04d2d0502ca652e67d2ddff6722bd37e-600-600"></a></p>

<p>For those of you without <a href="https://en.wikipedia.org/wiki/Hard_water">hard water</a>, our water in Canada like that of Italy, tends to be hard due to the type of rocks that water passes through on the way into our water supply. Over time, the hard water minerals precipitate out and stick to the metallic pipes and heaters within the machine, causing the temperature of the brewing water to drop, and other quality problems. <a href="https://www.kitchenaid.com/pinch-of-help/countertop-appliances/how-to-clean-and-descale-a-coffee-maker.html">Regular descaling</a> is recommended, and some modern machines feature special descaling modes and chemicals that make this easier to do.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-Map-of-water-hardness-of-Italian-tap-water-Classification-is-presented-in-the-legend.png"><img src="https://grack.com/_thumbs/c0aef4579e0ae0a88b3dacccb182dd61-600-600"></a></p>

<p>Figure: <a href="https://www.researchgate.net/publication/231520556_Major_and_Trace_Elements_in_Tap_Water_from_Italy">Major and Trace Elements in Tap Water from Italy</a> January 2012 <em>Journal of Geochemical Exploration 112:54-75</em> DOI:10.1016/j.gexplo.2011.07.009</p>

<p>To descale a machine, you generally use a weak acid like vinegar, or a more complex <a href="https://en.wikipedia.org/wiki/Descaling_agent">descaling agent</a> to dissolve the precipitate as salts so they can be flushed out. Unfortunately, the last time I ran the descaling process on this coffeemaker the acid I was using seems to have degraded one of the internal seals and the machine began to leak significantly.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-leak.jpeg"><img src="https://grack.com/_thumbs/b4a51f655be2153965b008e20a0068bf-600-600"></a></p>

<p>Faced with the prospect of opening it up and actually figuring out what part was leaking, I was finally convinced that given the amount of coffee we drink, it was time for us to invest in a more modern and little more upscale coffeemaker.</p>

<p>Fortunately a few months earlier over the same Spring, my partner had been TA’ing a course at a building in a nearby hospital over the summer and came home raving about a machine they had, that let her brew coffee from an application: the Delonghi Dinamica Plus. We talked about how cool it was to brew from an app and how it could make so many different drinks, but we both forgot about it for a few months until our the old machine failed.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-dinamica-plus.jpeg"><img src="https://grack.com/_thumbs/b520c81f57a2c16343ad0fb6dedae554-600-600"></a></p>

<p>Our coffee situation was pretty dire and we decided to pull the trigger on a Delonghi Dinamica Plus, despite the eye-watering price. We waited anxiously for a week, keeping the old coffeemaker in service by putting it inside a tray to catch the leaks.</p>

<p>When the new coffeemaker arrived we set it up and – to avoid a major digression – the coffee it made was excellent. Tasty espresso, perfect americano, creamy cappuccino. There was one major problem: the application you’re supposed to use for the coffeemaker doesn’t reliably connect and stay connected to the machine.</p>

<p>The <a href="https://www.delonghi.com/en-ca/dinamica-plus-smart-coffee-and-espresso-machine-with-coffee-link-connectivity-app-plus-automatic-milk-frother-titanium-ecam37095ti/p/ECAM37095TI">Dinamica Plus</a> is about $100 more than the <a href="https://www.delonghi.com/en-ca/dinamica-with-lattecrema-automatic-coffee-and-espresso-machine-with-iced-coffee-plus-automatic-milk-frother-silver-ecam35075si/p/ECAM35075SI">Dinamica</a>, and this cost is effectively for the privilege of brewing coffee from your phone (along with some other goodies, like defining your favourite or custom drinks from the couch). The application is difficult to use and a bit buggy, however. It will often fail to find the coffeemaker. Once you’ve connected, there’s no guarantee that it’ll allow you to connect again without wiping all the saved data from the application. It’s also integrated with some sort of online service that returns a 404.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-coffee-lounge-404.png"><img src="https://grack.com/_thumbs/264c3ee556c10dbb41229978cade1e7a-600-600"></a></p>

<p>I found myself at a crossroads here: Do I accept that the extra features that I paid for will go to waste, or do I dig in and see if there’s some way I can get this feature to work in a way that I can actually use it. There’s a lot you can learn by being forced to dig into something new, and it looked like this might be an opportunity to understand a bit more about Bluetooth. So, as you can probably guess from the remaining length on this topic, I took the latter path.</p>

<h2 id="btle-background-and-traffic-sniffing">BTLE Background and Traffic Sniffing</h2>

<p>The first question we need to answer is how we’re going to talk to this thing. We know it’s Bluetooth from the application’s insistence that Bluetooth be turned on. But it’s not showing up on my MacBook’s Bluetooth devices list, which means it’s somehow different than the common Bluetooth “Classic” audio and phone devices that show up there.</p>

<p>There may be other reasons why the coffeemaker doesn’t show up in a list of Bluetooth devices on a laptop, but the most likely candidate for something that isn’t Bluetooth Classic like those devices is <a href="https://learn.adafruit.com/introduction-to-bluetooth-low-energy">Bluetooth Low-Energy</a>, or more commonly known as BTLE.</p>

<p>One of BTLE’s major fame was its use in <a href="https://en.wikipedia.org/wiki/IBeacon">iBeacon</a> for the Apple ecosystem: a way of transmitting that a physical location was “interesting” in some way to some set of applications. This is done by <a href="https://os.mbed.com/blog/entry/BLE-Beacons-URIBeacon-AltBeacons-iBeacon/">“advertising”</a> Apple’s Bluetooth SIG identifier, along with an ID that specifies you’re talking iBeacon language, and some metadata allowing you to identify two 16-bit numbers of data along with that.</p>

<p>BTLE devices are often hidden from general device users, and you access them through specific programs and applications. For example, if you’re looking to rent a scooter, the app might communicate directly with the scooter over BTLE to unlock it for use directly from the phone – no cellular radio required!</p>

<p>We can scan for BTLE devices using an app like <a href="https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp">nRF Connect</a> that will show us all the nearby devices to our mobile phone. In the screenshot below you’ll see everything that speaks BTLE that my phone can see:</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-nRF-screenshot.png"><img src="https://grack.com/_thumbs/16a8fb83efb3c3fb814fcd3ab618fd67-600-600"></a></p>

<p>There’s no obvious coffeemaker here but we can start to make some educated guesses by using signal strength. We’ll walk from the couch to the coffeemaker and see that one of our BTLE devices shows an increasing signal level.</p>

<p>We can confirm that this is the right device by forcing a connection to it and seeing the same Bluetooth icon appear on the screen that also appears when the application connects.</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-connect.png"><img src="https://grack.com/_thumbs/b89f81a72a1128a2b442ace57bf9a1aa-600-600"></a></p>

<p>Aha! So now we’ve proved this coffeemaker is communicating over BTLE. But let’s digress and dig into what BTLE actually is, so we can figure out how to talk to it.</p>

<p>At a high level, BTLE works around the concept of a <em>Service</em> and a <em>Characteristic</em>, both identified by UUIDs. A <em>Service</em> is a container for <em>Characteristic</em>s and, at a high level, two services on two different devices sharing the same UUID will generally implement the same “protocol”. BTLE stacks on devices will generally allow you to scan for announcements of devices advertising a <em>Service</em> UUID you are interested in, allowing you to take inventory of supported devices relatively easily.</p>

<p>The <em>Characteristic</em> is an endpoint on the <em>Service</em> and has some directionality information embedded within it. A <em>Characteristic</em> at a high level provides <code>READ</code> and/or <code>WRITE</code> operations to communicate with the device, but also which of the devices in the connection can be the origin of this data (ie: does the device broadcast packets? will it send them unannounced? does the device only communicate if you send it something first?). <a href="https://devzone.nordicsemi.com/guides/short-range-guides/b/bluetooth-low-energy/posts/ble-characteristics-a-beginners-tutorial">Table 2 in this tutorial</a> lists the options if you’re interested in more detail.</p>

<p>We’ve learned some important information along the way. From our scan earlier, we know the two bits we need to communicate with the device, ie: the <em>Service</em> UUID is <code>00035b03-58e6-07dd-021a-08123a000300</code> and the <em>Characteristic</em> UUID is <code>00035b03-58e6-07dd-021a-08123a000301</code>.</p>

<p>What we need now is something to send to it. I’m not brave enough to brute force packets for an expensive coffeemaker, so let’s try to capture some real communication between the application and the device.</p>

<p>Android has something called the Bluetooth HCI snoop log that, as you can imagine, allows you to snoop on Bluetooth communication. HCI stands for “host-controller interface”, and we’ll use the snooper to log interaction between the phone and the coffeemaker. The process of enabling and retrieving HCI logs <a href="https://stackoverflow.com/questions/28445552/bluetooth-hci-snoop-log-not-generated">varies</a> <a href="https://medium.com/@charlie.d.anderson/how-to-get-the-bluetooth-host-controller-interface-logs-from-a-modern-android-phone-d23bde00b9fa">wildly</a> between device models, so your mileage may vary.</p>

<p>We can tap the button in the app to brew a cappuccino and, from the logs, see what the application sends to the machine. We don’t have any context as to what these packets are, but we know that sending this will brew a cappuccino with the default parameters (which according to the application is 65ml of coffee, 19 seconds of milk, and “medium” aroma):</p>

<pre><code>Brew a cappuccino:
0d 14 83 f0 07 01 01 00 41 09 00 be 02 03 0c 00 1c 02 06 dc

Device sends back:
d0 07 83 f0 01 00 64 d9

Cancel brewing:
0d 08 83 f0 07 02 06 2f 41

Device sends back:
d0 07 83 f0 01 00 64 d9
</code></pre>

<h2 id="communicating-in-rust">Communicating in Rust</h2>

<p>Now we’re going to need to talk to the coffeemaker ourselves. Each platform has its own libraries for talking to Bluetooth devices (CoreBluetooth on OSX, bluez-over-DBUS for Linux, etc.) Because of the complexity of dealing with cross-platform Bluetooth, most platforms like node.js, Rust, and Python, provide libraries that abstract this away.</p>

<p>My first attempts to talk to the coffeemaker were using node.js. I tried <a href="https://github.com/noble/noble">noble</a>, and <a href="https://github.com/noble/bleno">bleno</a>, but neither appeared to work for me on my Mac. I’ve been wanting to get my Rust skills back into shape, so I decided to explore the <a href="https://github.com/deviceplug/btleplug">btleplug</a> library which is being actively maintained on all modern platforms.</p>

<p>To connect to the device we’re interested in, first we need to start a scan to find devices that are advertising the <em>Service</em> and <em>Characteristic</em> we are interested in. The following code fragment will ask <code>btleplug</code> to scan for peripherals on every adapter connected to the system.</p>

<pre><code>async fn main() -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {
    let manager = Manager::new().await?;
    let filter = ScanFilter {
        services: vec![SERVICE_UUID],
    };

    eprintln!("Looking for coffeemakers...");
    for adapter in manager.adapters().await? {
        adapter.start_scan(filter.clone()).await?;
        tokio::time::sleep(Duration::from_secs(10)).await;
        for peripheral in adapter.peripherals().await? {
            eprintln!("Found peripheral");
            peripheral.connect().await?;
            peripheral.discover_services().await?;
            for service in peripheral.services() {
                for characteristic in service.characteristics {
                    if service.uuid == SERVICE_UUID &amp;&amp; characteristic.uuid == CHARACTERISTIC_UUID {
                        run_with_peripheral(peripheral.clone(), characteristic).await?;
                    }
                }
            }
        }
    }

    Ok(())
}

async fn run_with_peripheral(
    peripheral: Peripheral,
    characteristic: Characteristic,
) -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {
    eprintln!("{:?}", characteristic);
    Ok(())
}
</code></pre>

<p>If we run this code it, prints:</p>

<pre><code>Looking for coffeemakers...
Found peripheral
Characteristic { uuid: 00035b03-58e6-07dd-021a-08123a000301, service_uuid: 00035b03-58e6-07dd-021a-08123a000300, properties: READ | WRITE | INDICATE }
</code></pre>

<p>Looks good! We found the coffeemaker. And now we can try to send a raw packet to it that we had captured earlier that we believed was sent to brew cappuccino. Let’s change <code>run_with_peripheral</code> to this:</p>

<pre><code>async fn run_with_peripheral(peripheral: Peripheral, characteristic: Characteristic) -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {
    let data = &amp;[0x0d,0x14,0x83,0xf0,0x07,0x01,0x01,0x00,
        0x41,0x09,0x00,0xbe,0x02,0x03,0x0c,0x00,0x1c,0x02,0x06,0xdc]; 
    peripheral.write(&amp;characteristic, data, btleplug::api::WriteType::WithoutResponse);
    Ok(())
}
</code></pre>

<p>And hey, that started brewing a cappuccino!</p>

<p><a class="image standard" href="https://grack.com/assets/2022/12/part-1-cappuccino.jpeg"><img src="https://grack.com/_thumbs/2648c801f7556860ebd9ead82bef9cdd-600-600"></a></p>

<p>Let’s take stock of where we are:</p>

<ul>
  <li>We know how to communicate with the device</li>
  <li>We know the UUIDs of the endpoint that we’re going to communicate with</li>
  <li>We can write a packet to the device and see that it performs an action</li>
</ul>

<p>This might be enough to stop here. We could trace all the packets to brew all the coffee recipes we want, but that doesn’t seem like a complete solution.</p>

<p><a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2"><em>Continue reading…</em></a> In <a href="https://grack.com/blog/2022/12/02/hacking-bluetooth-to-brew-coffee-on-github-actions-part-2">part two</a> of the series we’ll reverse engineer the protocol itself!</p>

<h2 id="further-reading-for-this-post">Further reading for this post</h2>

<ul>
  <li><a href="https://learn.adafruit.com/introduction-to-bluetooth-low-energy">Adafruit: Introduction to Bluetooth Low-Energy</a></li>
  <li><a href="https://os.mbed.com/blog/entry/BLE-Beacons-URIBeacon-AltBeacons-iBeacon/">Understanding the different types of BLE Beacons</a></li>
  <li><a href="https://devzone.nordicsemi.com/guides/short-range-guides/b/bluetooth-low-energy/posts/ble-characteristics-a-beginners-tutorial">BTLE Characteristics, a beginner’s tutorial</a></li>
  <li><a href="https://medium.com/@charlie.d.anderson/how-to-get-the-bluetooth-host-controller-interface-logs-from-a-modern-android-phone-d23bde00b9fa">How to get BT Host Controller Interface logs from a modern Android phone</a></li>
</ul>

<p><strong><em><a href="https://hachyderm.io/@mmastrac">Follow me on Mastadon</a> for more updates on this adventure!</em></strong></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Opinionated Dress Color Simulator]]></title>
		<link href="https://grack.com/blog/2015/03/01/opinionated-dress-color-simulator"/>
		<updated>2015-03-01T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2015/03/01/opinionated-dress-color-simulator</id>
		<content type="html"><![CDATA[<p>Given the all the fuss over the <a href="http://www.buzzfeed.com/catesish/help-am-i-going-insane-its-definitely-blue">blue/black or white/gold dress</a> this week, I whipped up a <a href="https://grack.com/demos/dress">quick simulation</a> that allows you to view the dress under different lighting conditions.</p>

<p><a class="image standard" href="https://grack.com/assets/2015/03/dress-screenshot.png"><img src="https://grack.com/_thumbs/aa556c2471d02a66eedf1850c386f867-600-600"></a></p>

<p>Slide the control from side-to-side to fade between the three images: a “blue/black” version where we subtract out the theoretical color of the light (#524922), the original picture, and a “white/gold” version where we add color to compensate for the perceived shadow (#392c00).</p>

<p><a href="http://qz.com">qz.com</a> picked this up and <a href="http://qz.com/352594/use-this-slider-to-see-the-dress-change-colors-before-your-very-eyes/">created their own version as well</a>.</p>

<p>Grab the source <a href="https://github.com/mmastrac/dress-simulator">from GitHub</a>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[USB-C and Modular Smartphones Are the End-Game for Convergence]]></title>
		<link href="https://grack.com/blog/2015/01/16/usb-31-ara-are-the-convergence-end-game"/>
		<updated>2015-01-16T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2015/01/16/usb-31-ara-are-the-convergence-end-game</id>
		<content type="html"><![CDATA[<p>Two new technologies – the modular smartphone and USB 3.1 – are set to radically accelerate the convergence of everything to a single, in-pocket device. In fact, they are so revolutionary that they will change the entire way we think about mobile computing <a href="http://ben-evans.com/benedictevans/2015/1/11/resetting-the-score">as the iPhone did</a> earlier this millennium.</p>

<h1 id="modules-will-eat-custom-hardware">Modules will eat custom hardware</h1>

<p>Modular smartphones, the first of which being <a href="http://www.projectara.com/">Project Ara</a>, will <a href="http://www.engadget.com/2015/01/14/project-ara-spiral-3/?ncid=rss_truncated">shift the way we buy devices</a> while opening up new markets.</p>

<iframe width="560" height="315" src="//www.youtube.com/embed/intua_p4kE0" frameborder="0" allowfullscreen=""></iframe>

<p>The backbone of Project Ara is <a href="http://en.wikipedia.org/wiki/UniPro">UniPro</a> – a standard for communication not unlike Intel’s Thunderbolt – with <a href="http://www.arrowdevices.com/blog/mipi-unipro-through-eyes-of-pci-express/">significant bandwidth</a>, enough to push 4k video uncompressed between them. Modules are built on top of this high-speed network.</p>

<p><a class="image floatright" href="https://grack.com/assets/2015/01/ara/lytro.jpg"><img src="https://grack.com/_thumbs/7a7e68dd61e821ef6f70065ba82f4d2e-600-600" align="right" width="200"></a>The current pipeline for a “revolutionary” add-on in the mobile space has many gatekeepers. When FLIR wanted to launch a smartphone IR camera, they needed to <a href="http://www.flir.com/flirone/explore.cfm">build an entire phone backpack</a> around it.</p>

<p>Another company, Lytro, has no smartphone equivalent to their light-field camera. Instead, you need to buy an entire <a href="http://amzn.to/1B2Dlr5">custom camera</a> or <a href="https://store.lytro.com/products/lytro-illum">point-and-shoot</a> system which significantly adds to the cost of the system, and requires the end-user to commit to carrying a full, purpose-built device.</p>

<p><a class="image floatleft" href="https://grack.com/assets/2015/01/ara/spike.jpg"><img src="https://grack.com/_thumbs/08ec42b5b093c107423afa8e28875456-600-600" align="left" width="200"></a>The same story is playing out in the construction space. <a href="https://www.kickstarter.com/projects/ikegps/spike-laser-accurate-measurement-and-modelling-on">Laser</a> <a href="http://gizmodo.com/this-laser-smartphone-add-on-accurately-measures-everyt-1489061539">measuring</a> tools are following in the same backpack space. Unsurprisingly, the same pattern of building significant packaging around simple components has played out for <a href="https://www.ryobitools.com/phoneworks/">construction tools</a>, <a href="http://www.mophie.com/shop/iphone-5">battery cases</a>, <a href="http://amzn.to/1xZVS50">high-end cameras</a>, and <a href="http://www.bbc.com/news/technology-25663424">Tazers</a> as well.</p>

<p>The obvious advantage to an Ara-like device is that manufacturers can bring a module to market without the traditional risk-averse gatekeepers in the manufacturer (Samsung, LG, etc.) and carriers (AT&amp;T, Verizon, etc.). If the manufacturers decide that this custom module isn’t a fit for their mass-market devices, they’ll pass.</p>

<p>Rather than Lytro or a small Kickstarter team convincing one of the big names to include their custom module at significant risk to both parties, the team can produce the module themselves and directly market to end-users without the overhead of developing a bulky backpack add-on.</p>

<p><a class="image standard" href="https://grack.com/assets/2015/01/ara/tazer.png"><img src="https://grack.com/_thumbs/ee9f570a0096f95ce717f03402d2db7d-600-600"></a><a class="image standard" href="https://grack.com/assets/2015/01/ara/ryobi.jpg"><img src="https://grack.com/_thumbs/f4f42969a4eccaff6d2006423ba19d4f-600-600"></a></p>

<p>By subverting the manufacturer channels, this significantly de-risks the process of bringing new concepts to market and will open up a flood of novel ideas.</p>

<p>Module development provides another channel for manufacturers to rely on the smartphone to be the “brains” of their devices. Making a custom device OS and shell will no longer make sense for companies like FLIR and Fluke when building IR cameras and <a href="http://en.wikipedia.org/wiki/Borescope">borescopes</a> for a large part of their product line – at least the products that can be used outside of emergency situations. While this is possible now through Bluetooth or audio jack hacks like <a href="https://www.ryobitools.com/phoneworks/">Ryobi’s phoneworks</a>, making a module will make more sense.</p>

<h1 id="usbs-type-c-one-cable-to-rule-them-all">USB’s type-C: one cable to rule them all</h1>

<p><a class="image floatright" href="https://grack.com/assets/2015/01/ara/usb-c.jpg"><img src="https://grack.com/_thumbs/c85153c6db8f0e44e65ffbd9c509ced4-600-600" align="right" width="200"></a><a href="http://www.cnet.com/news/usb-type-c-one-cable-to-connect-them-all/">USB 3.1 and the type-C cable</a> give us the ability to reliably connect a device to external components – even those requiring high bandwidth. By plugging in a single cable, you’ll have access to <a href="http://www.arrowdevices.com/blog/usb-31-vs-usb-30-technical-comparison/">over 10 Gb/s</a> of bandwidth for transmitting USB data. In addition, the type-C cable can be used in <a href="http://www.anandtech.com/show/8558/displayport-alternate-mode-for-usb-typec-announced">“alternate modes” like DisplayPort</a> for pushing video outside of the USB protocol.</p>

<p>What USB-C will enable is the ultimate computing convergence. When you’re at home or work and need to use the “big” screen, along with keyboard and mouse, you’ll plug into a desktop dock. <a class="image floatright" href="https://grack.com/assets/2015/01/ara/belkin.png"><img src="https://grack.com/_thumbs/170967ea9dfe149a005419ba475859a8-600-600" align="right" width="200"></a>This is already something happening for MacBooks: you can plug a single Thunderbolt cable into a dock and get access to a wide variety of ports.</p>

<p>If you need a larger experience, but don’t want to be tied to a desk, the laptop dock will be your friend. Motorola’s Atrix was the first rough iteration of this idea. It required both a USB micro and HDMI connection and it was tied to a single device. With the USB type-C connector, we will have the ability to plug a single cable into an supported device while getting video out and pushing power and keyboard/trackpad in.</p>

<p><a class="image standard" href="https://grack.com/assets/2015/01/ara/atrix.jpg"><img src="https://grack.com/_thumbs/7efb21d09b3b92155d41661550c8677e-600-600"></a></p>

<h1 id="the-future">The Future</h1>

<p>The era of the laptop and personal computer will eventually come to an end, but not until they allow developers and power users to do everything they can on high-end devices as easily on mobile devices. Before this can happen professionals of all sorts, the power users of the various platforms will need as much memory and processing power as they are currently using.</p>

<p>The type-C connector gets us part of the way there by moving graphics and input off your mobile device, but you’ll still be processing with whatever you can carry with you on your phone. While processor speeds will be improving the mobile space, it is likely that chips on larger boards will always be more powerful.</p>

<p>What we’ll see is the evolution of devices that can move computation from one place to another, in near-real-time. You’ll carry a modular smartphone on your person and have a more powerful version in desktop or laptop form. Plugging the device into the larger form factor will move your computation over to a more powerful CPU/GPU with significantly more RAM. You’ll bring your storage with you – the experience of computing will expand and contract depending on where you are and what you need.</p>

<p>We’re not far away from this right now. With applications running on JIT systems like Dalvik, the same code can be run on two different CPU types and the same techniques we use to juggle Javascript between interpreted and optimized states can transport an application between them.</p>

<p>Your pocket device will be the center of your digital life: a single mobile device when you’re on the go that can act as everything you need for work and play, an entertainment source and gaming console when you’re at home in front of your TV, the storage for your laptop when you need to work on the go, and the core of your desktop computing environment for the professionals who need high performance.</p>

<p><em>Thoughts?</em> Follow me on Twitter <a href="https://twitter.com/mmastrac">@mmastrac</a> and let me know.</p>

<p>Translations: <a href="http://softdroid.net/usb-and-modular-smartphones">Пост доступен на сайте softdroid.net</a>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[What's new in CSS Selectors 4]]></title>
		<link href="https://grack.com/blog/2015/01/11/css-selectors-4"/>
		<updated>2015-01-11T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2015/01/11/css-selectors-4</id>
		<content type="html"><![CDATA[<p><em>Please note that this article is written about an Editor’s Draft of a specification as of January 2015, which means the information may change without notice</em></p>

<p><a href="http://dev.w3.org/csswg/selectors-4/">CSS Selectors Level 4</a> is the next iteration of the CSS selector spec, the last version of which was <a href="http://www.w3.org/TR/css3-selectors/">made a recommendation in 2011</a> after being a working draft for a number of years.</p>

<p>So, what’s new?</p>

<h1 id="selector-profiles">Selector Profiles</h1>

<p>CSS selectors are now categorized into two groups: <em>fast</em> and <em>complete</em>. <em>Fast</em> selectors are those selectors appropriate for use in a dynamic CSS engine. <em>Complete</em> selectors are appropriate for use in cases where being as fast as possible isn’t necessarily a problem, <a href="https://developer.mozilla.org/en-US/docs/Web/API/document.querySelector"><code>document.querySelector</code></a>, for instance.</p>

<blockquote>
  <p>Selectors are used in many different contexts, with wildly varying performance characteristics. Some powerful selectors are unfortunately too slow to realistically include in the more performance-sensitive contexts. To accommodate this, two profiles of the Selectors spec are defined <a href="http://dev.w3.org/csswg/selectors-4/#profiles">[ref]</a>.</p>
</blockquote>

<h1 id="has">:has</h1>

<p><code>:has</code> is the most interesting part of CSS Selectors 4, but it comes with an important caveat described below. What it allows you to do is change the subject of the selector – i.e., the element that will actually be styled – while continuing to match elements that appear later in document order.</p>

<p>This opens up a great deal of new ways to match content. For instance, matching sections with a header:</p>

<pre><code>// Any section that has a header element
section:has(h1, h2, h3, h4, h5, h6)
</code></pre>

<p>Or a developer can match all paragraphs that contain nothing but any number of images:</p>

<pre><code>// Match a paragraph that does not have anything that is not an image
p
  :has(img)             // has an image
  :not(:has(:not(img))) // does not have anything not an image
</code></pre>

<p>Even matching an element that has a specific number of children (in this case, five):</p>

<pre><code>// Sidebar with five children
div.sidebar
    :has(*:nth-child(5))       // Has a fifth child
    :not(:has(*:nth-child(6))) // But not a sixth child
</code></pre>

<p>Caveat: at this time the <code>:has</code> selector is not considered <em>fast</em>, which means that it may not be available for use in stylesheets. As nobody has implemented this selector yet, its performance characteristics are still an open question. If browser vendors can make it fast, it may be available for general styling as well.</p>

<p>In <a href="http://www.w3.org/TR/2013/WD-selectors4-20130502/#subject">previous versions</a> of the specification this was indicated using an exclamation mark (<code>!</code>) next to the subject – that syntax is now gone.</p>

<h1 id="matches">:matches</h1>

<p><code>:matches</code> is a standardization of <code>:moz-any</code> and <code>:webkit-any</code> that have <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:any">existed with browser prefixes</a> for some time. This allows a stylesheet author to collapse duplicate rule paths.</p>

<p>This will be useful for collapsing generated Cartesian-product-esque SCSS/SASS output like this:</p>

<pre><code>  body &gt; .layout &gt; .body &gt; .content .post p a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body &gt; .layout &gt; .body &gt; .content .post p a.image.standard:first-child:nth-last-child(4), 
  body &gt; .layout &gt; .body &gt; .content .post li a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body &gt; .layout &gt; .body &gt; .content .post li a.image.standard:first-child:nth-last-child(4), 
  body &gt; .layout &gt; .body &gt; .content .page p a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body &gt; .layout &gt; .body &gt; .content .page p a.image.standard:first-child:nth-last-child(4), 
  body &gt; .layout &gt; .body &gt; .content .page li a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body &gt; .layout &gt; .body &gt; .content .page li a.image.standard:first-child:nth-last-child(4) {
       ....
  }
</code></pre>

<p>into the slightly more manageable:</p>

<pre><code>  body &gt; .layout &gt; .body &gt; .content 
    :matches(.post, .page) 
    :matches(p, li) 
    :matches(a.image.standard:first-child:nth-last-child(4), 
             a.image.standard:first-child:nth-last-child(4) ~ a.image.standard), 
       ....
  }
</code></pre>

<p>The Mozilla reference page above lists some caveats about performance. As this selector makes it out into a standard, we will hopefully see performance work on this to make it leaner.</p>

<h1 id="nth-childanb-of-s">:nth-child(An+B [of S])</h1>

<p>While <code>:nth-of-type</code> has existed <a href="http://www.w3.org/TR/2001/CR-css3-selectors-20011113/">since the turn of the millennium</a>, CSS Selectors Level 4 is adding the ability to filter based on a selector:</p>

<pre><code>div :nth-child(2 of .widget)
</code></pre>

<p>The selector <code>S</code> is used for determining the index and it is independent of the selector to the left of the pseudo-class. As noted in the specification, if you know the type of the element ahead of time the <code>:nth-of-type</code> selector can be converted into <code>:nth-child(... of S)</code> like so:</p>

<pre><code>img:nth-of-type(2) =&gt; :nth-child(2 of img)
</code></pre>

<p>The difference between this selector and the <code>:nth-of-type</code> selector is subtle but important. For <code>:nth-of-type</code>, each element –whether or not you have applied a selector to it – has an implicit index for itself amongst its siblings with the same tag name.  The selector in the <code>:nth-child(n of S)</code> expression creates a new counter each time you use a new selector.</p>

<p>There’s potential for bugs with this new selector. Since the selector inside the <code>:nth-child</code> pseudo-class is independent of the selector to the left of it, you can accidentally omit your subject if you specify a selector to the left that isn’t a superset of the selector inside of <code>:nth-child</code>. For example:</p>

<pre><code>tr:nth-child(2n of [disabled])
</code></pre>

<p>might not work as you expect if another, non-<code>&lt;tr&gt;</code> element has the <code>disabled</code> attribute.</p>

<p>In previous versions of the specification this was the <code>:nth-match</code> selector.</p>

<h1 id="not">:not()</h1>

<p>While you might have been using <code>:not</code> for some time, you’ll now be able to pass multiple arguments to it to save some bytes and typing:</p>

<pre><code>// Equivalent to:
//    :not(h1):not(h2):not(h3)...
:not(h1, h2, h3, h4, h5, h6)
</code></pre>

<h1 id="descendant-combinator-">Descendant combinator (&gt;&gt;)</h1>

<p>The <a href="http://dev.w3.org/csswg/selectors-4/#descendant-combinators">descendant combinator</a> has existed in CSS from the beginning as a space ( ), but now there’s an explicit version of it:</p>

<pre><code>// Equivalent to:
//    p img { ... }
p &gt;&gt; img { ... }
</code></pre>

<p>The reasoning for this is to provide a bridge between the direct descendant (<code>&gt;</code>), and the shadow DOM (<code>&gt;&gt;&gt;</code>) operator.</p>

<h1 id="column-combinator--and-nth-column">Column combinator (||) and :nth-column</h1>

<p>CSS Selectors 4 adds column operations that will allow stylesheet developers to more easily style individual columns in a table. The current approach to table styling requires using <code>:nth-child</code>, which does not always match up with table columns when using <code>colspan</code> attributes.</p>

<p>By using the new column combinator (<code>||</code>) you can now style table cells that are in the same column as a given <code>&lt;col&gt;</code> element:</p>

<pre><code>// The following example makes cells C, E, and G yellow. 
// (example taken from the CSS Selectors 4 specification)
col.selected || td {
  background: yellow;
  color: white;
  font-weight: bold;
}

&lt;table&gt;
  &lt;col span="2"&gt;
  &lt;col class="selected"&gt;
  &lt;tr&gt;&lt;td&gt;A &lt;td&gt;B &lt;td&gt;C
  &lt;tr&gt;&lt;td colspan="2"&gt;D &lt;td&gt;E
  &lt;tr&gt;&lt;td&gt;F &lt;td colspan="2"&gt;G
&lt;/table&gt;
</code></pre>

<p>Alternatively, a stylesheet author may use <code>:nth-column</code> and <code>:nth-last-column</code> to style cells.</p>

<p>In either case, if a cell spans multiple columns it will match a selector for any of those columns.</p>

<h1 id="placeholder-shown">:placeholder-shown</h1>

<p>One small addition to the selector language is <code>:placeholder-shown</code>. This matches an input element if and only if the <code>placeholder</code> attribute text is visible.</p>

<h1 id="any-link">:any-link</h1>

<p>The <code>:any-link</code> is another small selector addition. It is defined as matching anything that <em>either</em> <code>:link</code> or <code>:visited</code> would match.</p>

<pre><code>// Equivalent to:
//    a:link, a:visited { ... } 
a:any-link { ... }
</code></pre>

<h1 id="conclusions">Conclusions</h1>

<p>CSS Selectors 4 is still a work-in-progress, but there are already useful selectors that we’ve seen that will offer web developers new patterns and tools for styling. There are <a href="http://dev.w3.org/csswg/selectors-4/">other new selectors</a> in the specification that I haven’t discussed here for concepts like accessibility, validity checking and style scoping.</p>

<p>If you’d like to play around with these selectors, you’ll need to wait for browsers vendors to catch up, or use some of the earlier implementations. <code>:matches</code> is available as <code>:moz-any</code> and <code>:webkit-any</code>, and WebKit nightlies have early support for <a href="http://lists.w3.org/Archives/Public/www-style/2014Oct/0106.html"><code>:nth-child</code> selectors behind a flag</a>.</p>

<p>Since this is an editor’s draft, pseudo-class names may change without notice. Keep an eye on the <a href="http://dev.w3.org/csswg/selectors-4">specification</a> for more information.</p>

<p><em>Comments?</em> Follow me on Twitter <a href="https://twitter.com/mmastrac">@mmastrac</a> and let me know.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[(Ab)using CSS3's :nth-child selector to invent new ones]]></title>
		<link href="https://grack.com/blog/2015/01/09/abusing-css3-selectors"/>
		<updated>2015-01-09T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2015/01/09/abusing-css3-selectors</id>
		<content type="html"><![CDATA[<p><em>If you find this interesting, read more about <a href="https://grack.com/blog/2015/01/11/css-selectors-4">CSS Selectors Level 4</a> which will offer you even more tools for stylesheet development.</em></p>

<p>CSS3’s <code>:nth-child</code> and <code>:nth-last-child</code> selectors are powerful: not only can they replace <code>:first-child</code> and <code>:last-child</code>, but they can style more complex patterns like the first (or all but the first) three children, every fourth child, or combinations of the pattern “a*n+b”.</p>

<p>But did you know that you can do more interesting things with the selectors? For example, you can style the third element, but only when it’s one of five child (the virtual <code>:nth-of-m-child</code> selector we’ll discuss below). Or that you can style all of the children of an element with <code>m</code> children (another virtual selector we’ll call <code>:family-of-m</code>).</p>

<p>You might ask why we’d want to do this – the particular use case that I had in mind was a Javascript-free, automatically-sizing image gallery that I could toss in the stylesheet for my Jekyll-based site and have it “just work” regardless of the number of images I threw at it.</p>

<p>Here’s an example of what it looks like (click <a href="https://grack.com/assets/2015/01/nth-child/image-count.html">here</a> to view it full-page). Note how the images automatically size to a regular grid without having to use Javascript:</p>

<iframe style="width: 100%; height: 400px;" src="https://grack.com/assets/2015/01/nth-child/image-count.html"></iframe>

<h1 id="nth-of-m-child">:nth-of-m-child</h1>

<p><em>Thanks to <a href="https://news.ycombinator.com/item?id=8863732">xantys</a> on HN for pointing me at much earlier work in this area <a href="http://lea.verou.me/2011/01/styling-children-based-on-their-number-with-css3/">here</a> and <a href="http://andr3.net/blog/post/142">here</a>.</em></p>

<p>The first virtual selector we’ll construct is something I call <code>:nth-of-m-child</code>. This will allow us to style the nth child when it’s one of m children, and will be our building block for further work.</p>

<p>So, how do we get this selector? Easy: we combine <code>:nth-child</code> and <code>:nth-last-child</code> on a single element to select when the element to be styled is in the correct position from the start and end of the list of children. For example, we can style the third element, if and only if it’s one of five children:</p>

<pre><code>span:nth-child(3):nth-last-child(3) { ... }
</code></pre>

<p>Breaking that down: that’s the third child and the third-last child. Given ‘n’ and ‘m’, the general formula is <code>:nth-child(n):nth-last-child(m+1-n)</code>.</p>

<p>Here’s an example of this in action (click <a href="https://grack.com/assets/2015/01/nth-child/nth-test.html">here</a> to view it full-page):</p>

<iframe style="width: 100%; height: 400px;" src="https://grack.com/assets/2015/01/nth-child/nth-test.html"></iframe>

<h1 id="family-of-m">:family-of-m</h1>

<p>Now that we have the ability to style n-of-m, we can expand that out to style all of the children where there are m of them directly underneath a parent node. The secret to this is using the CSS3 <code>~</code> non-adjacent sibling selector which will continue matching elements across siblings. For example, the selector:</p>

<pre><code>img ~ span { ... }
</code></pre>

<p>will match a <code>&lt;span&gt;</code> if and only if one of its previous siblings was an <code>&lt;img&gt;</code> element regardless of the number of siblings between them. We’ll combine this selector with our <code>:nth-of-m-child</code> pattern like so:</p>

<pre><code>span:nth-child(1):nth-last-child(5) ~ span { ... }
</code></pre>

<p>This pattern will match any adjacent siblings to the first element of five, ie: the second through the fifth of five. We can make it match the entire row by using a comma to match the first element as well.</p>

<pre><code>span:nth-child(1):nth-last-child(5), 
	span:nth-child(1):nth-last-child(5) ~ span { ... }
</code></pre>

<p>Here’s an example of this in action (click <a href="https://grack.com/assets/2015/01/nth-child/nth-family-test.html">here</a> to view it full-page):</p>

<iframe style="width: 100%; height: 400px;" src="https://grack.com/assets/2015/01/nth-child/nth-family-test.html"></iframe>

<h1 id="advanced-techniques">Advanced techniques</h1>

<p>Alright, now we have the tools in place for us to style images <a href="https://grack.com/assets/2015/01/nth-child/image-count.html">as seen in the example</a>.</p>

<p>The first grouping of one through four are simple applications of the technique. When we get to five we want to start using a pattern where the first line or two are larger pairs and the remainder of the images are in triplets. This pattern should repeat regardless of the number of images.</p>

<p>Here’s a commented example. Note that this might potentially be simplified using flexbox and wrapping, but that’s an exercise for the reader.</p>

<p>Let’s start with fifth, eighth, eleventh and the remainder of this pattern. Instead of using the <code>:nth-child(1):nth-last-child(...)</code> as we did before, we’ll use <code>:nth-child(1):nth-last-child(3n+5)</code>. This will match the first element of a grouping of 5, 8, 11, …:</p>

<pre><code>/* First two are half-sized (99% / 2) */
img:first-child:nth-last-child(3n+5) ~ img, img:first-child:nth-last-child(3n+5) {
	max-width: 49.5%;
	margin-right: 1%;
}

/* Last n - 2 are (98% / 3) */
img:first-child:nth-last-child(3n+5) + img ~ img {
	max-width: 32.6%;
	margin-right: 1%;
}

/* But second, fifth, eighth, ... have no right margin */
img:first-child:nth-last-child(3n+5) ~ img:nth-child(3n+2) {
	margin-right: 0;
}
</code></pre>

<p>Six, nine, and twelve are much simpler.</p>

<pre><code>/* Six, nine, twelve, ... are all (98% / 3) */
img:first-child:nth-last-child(3n+6) ~ img, img:first-child:nth-last-child(3n+6) {
	max-width: 32.6%;
	margin-right: 1%;
}

/* Every third one of these has no right margin. */
img:first-child:nth-last-child(3n+6) ~ img:nth-child(3n) {
	margin-right: 0;
}
</code></pre>

<p>Seven, ten, thirteen, and the remainder of the pattern are similar to the 5/8/11 pattern:</p>

<pre><code>/* First four are half-sized (99% / 2) */
img:first-child:nth-last-child(3n+7) ~ img, img:first-child:nth-last-child(3n+7) {
	max-width: 49.5%;
	margin-right: 1%;
}

/* Last n - 4 are (98% / 3) */
img:first-child:nth-last-child(3n+7) + img + img + img ~ img {
	max-width: 32.6%;
	margin-right: 1%;
}

/* The second and fourth, seventh, tenth, ... have no right margin */
img:first-child:nth-last-child(3n+7) + img, 
	img:first-child:nth-last-child(3n+7) ~ img:nth-child(3n+4) {
	margin-right: 0;
	outline: 1px solid red;
}
</code></pre>

<h1 id="conclusions-notes-and-further-work">Conclusions, notes, and further work</h1>

<p>We can do some really interesting things making using of <code>:nth-child</code> and sibling selectors. The techniques in this post will also work for the related selectors <code>:nth-of-type</code> and <code>:nth-last-of-type</code>.</p>

<p>Browser performance doesn’t appear to be noticeably affected on mobile or desktop using this technique. If you plan on scaling this up it’s obviously something you’ll want to test.</p>

<p>If you were to combine this with flexbox and <a href="http://css-tricks.com/almanac/properties/f/flex-wrap/">flex-wrap</a> you might be able to simplify the example even further and might be able to handle images of different sizes more elegantly.</p>

<p>You also can also use this to create other interesting patterns, like matching only when the total number of children is even or odd, or other factor-based qualifiers.</p>

<p>I’d love to hear of any ideas or improvements you might have. Play around with <a href="http://jsfiddle.net/asmr1583/">the JSFiddle</a> here.</p>

<p>Thanks to <a href="https://www.webucator.com/">Webucator</a> for creating a video for this post as part of their <a href="https://www.webucator.com/webdesign/css.cfm?productTypeName=&amp;versionPageName=css3">CSS3 training</a> course series:</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/hBqshBv8Hes" frameborder="0" allowfullscreen=""></iframe>

<p><em>Comments?</em> Follow me on Twitter <a href="https://twitter.com/mmastrac">@mmastrac</a> and let me know.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Welcome to the new grack.com]]></title>
		<link href="https://grack.com/blog/2015/01/08/welcome-to-the-new-grack-com"/>
		<updated>2015-01-08T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2015/01/08/welcome-to-the-new-grack-com</id>
		<content type="html"><![CDATA[<p>I’m now on my fifth – though I’m sure not my last – iteration of blog management, <a href="http://jekyllrb.com/">Jekyll</a>. It’s a slick static site generator and from what I can tell, <a href="https://www.staticgen.com/">the most popular</a>.</p>

<p>One of the benefits of a static site generation tool is that you can aggressively cache the content. For that I’ve thrown <a href="http://cloudflare.com/">Cloudflare</a> in front of everything and have it both caching and optimizing all of my assets.</p>

<p>As part of the re-launch I wanted to offer some basic site search. I looked into <a href="http://lunrjs.com/">a few options</a> for static search in pure Javascript, but the most convenient turned out to be <a href="http://swiftype.com/">Swiftype</a> which was not much more work than clicking a switch on Cloudflare’s app page.</p>

<p><a class="image standard" href="https://grack.com/assets/2015/01/swiftype.png"><img src="https://grack.com/_thumbs/de0d0ab8a1e1a9787fa47c7f76cc12a0-600-600"></a></p>

<p>While I was somewhat happy on <a href="https://wordpress.org">Wordpress</a>, my <a href="https://grack.com/blog/2010/03/14/a-decade-and-three-blogging-platforms-later">biggest issue</a> with it was that everything lived in a database rather than source control, and that it required constant attention updating it for each release. I spent <a href="https://grack.com/blog/2009/04/11/yet-another-blog-engine">nearly five years</a> on the platform, however, which puts it at the longest I’ve stayed on any one tool.</p>

<p>Obviously, publishing posts with static site generators isn’t quite as convenient. For that I’m making use of <a href="https://travis-ci.org/">Travis CI</a> and a private GitHub repo. It runs <a href="http://www.linklint.org/">linklint</a> over everything, then pushes it out to the static host via <code>rsync</code>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[The Next Decade: part 2]]></title>
		<link href="https://grack.com/blog/2014/12/06/the-next-decade-part-2"/>
		<updated>2014-12-06T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2014/12/06/the-next-decade-part-2</id>
		<content type="html"><![CDATA[<p>Five years ago <a href="https://grack.com/blog/2010/01/03/the-next-decade">I wrote a set of predictions about 2020</a>. In some ways I think I was too unambitious for the progress of technology: browser technology has probably already reached the levels I had expected for a decade later. Some of them look like they might be off-target, like the increase in storage capacity of mobile devices. We still have another five years to see how they all pan out.</p>

<p>I thought I’d take another swing at a set of predictions. This time I’m looking out towards 2025.</p>

<h3 id="manufacturing">Manufacturing</h3>

<p>3D printing is the next major transformative technology wave. In 2025 we’ll be seeing 3D printers in the homes of at least a quarter of North Americans. Home 3D printer quality in 2025 will be amazing. A consumer will be able to print in multiple colors and plastic/rubber-like materials, with a final print quality that will often rival that of mold-formed products.</p>

<p>There will be multiple marketplaces for things to print: some open-source ones that will contain basic shapes and designs, and a number of licensed repositories for printing designer items like toys and kitchenware from well-known names. There will also be a healthy 3D piracy community.</p>

<p>When you look around a room in 2014, a lot of what you see will be printed in the home or a rapid-manufacturing facility in 2025. 3D printing will eat the manufacturing lifecycle from the bottom up. Products where the first 100 might be built with rapid prototyping today will have the first 100,000 produced on-demand. Companies like IKEA will choose to print and cut their designs on-demand in warehouses rather than stocking parts built elsewhere.</p>

<p>Local distribution centers will replace overseas manufacturing almost completely. North America will import processed materials from China, India and Africa for use in the new local centers: plastics and rubbers, and metals with binder. The local manufacturing centers will use a combination of 3D printer, laser/plasma cutting and generic robot assembly to build everything from one-off orders to runs of thousands as needed.</p>

<p>To support rapid manufacturing at these levels, generic robotics will replace the manufacturing line of today. A generic robot will be able to be taught to do a task like a human does and will coordinate with other generic robots to build a product like a fixed line would do today. Generic robotics will also find itself at home in other fields currently employing humans doing repetitive tasks like food preparation, laundry and cleaning.</p>

<p>Amusingly 3D printers will be <em>displacing</em> regular document printers which will have mostly died out at that point. Paper will take much longer than 2025 to replace, but the majority of financial, legal and educational work will be entirely electronic. Electronic signatures will be commonplace and some form of e-signature using mobile devices and biometrics will likely be used to validate documents. Paper in the home will be well on its way out and even children will be coloring on electronic devices with a stylus rather than coloring books.</p>

<h3 id="home">Home</h3>

<p>In 2025 we’ll have maxed out our technologies for 2D display and audio. Screens on cheap devices will have the same effective DPI as paper and the pixel will be something very few people will see. Virtual reality won’t be pervasive yet, but it’ll be in a significant number of homes for entertainment purposes. There will be devices small enough for portable use.</p>

<p>The convergence of devices will continue, and will consume a number of devices for entertainment at home. The cable box and dedicated game consoles will be almost dead, replaced with streaming from personal devices Chromecast-style. TV will still be going strong and there will be advancements in display technology that will allow basic 3D technology without glasses using light-field manipulation.</p>

<h3 id="transport">Transport</h3>

<p>Vehicles will be radically transformed by advances in self-driving technology. While we still won’t have pervasive self-driving vehicles, there will be a large number of autonomous vehicles on the road. These will mainly replace long-haul trucking and transport, but some higher-end vehicles will be autonomous enough to allow individuals to safely commute to work or run errands hands-free.</p>

<p>Car ownership will be dramatically declining by 2025. With the ability to summon transport from an autonomous or human-driven vehicle at the tip of everyone’s fingertips, it won’t make sense for most people to own vehicles. High-end cars will continue to be a status symbol, but the low-end market will be decimated in the transition.</p>

<p>Electric vehicles will have captured around half of the market of vehicles sold, including everything from passenger cars to transport trucks. Fossil fuels and hydrogen will be included as “backup” options on some models, used only to increase range if needed by charging the batteries.</p>

<h3 id="energy">Energy</h3>

<p>With solar getting cheaper and more efficient year-by-year, we’ll see some changes in the way that energy is supplied to home. Neighborhood grids will replace nation-wide grids for home use. Dozens of houses will pool their solar power into a cooperative with battery storage that they’ll use for electricity, heating and charging of vehicles.</p>

<p>More nuclear power will come online in the 2020’s, mainly driven by new reactor designs that produce very little waste and advances in fail-safe technology. Thorium-based reactors will be just starting to appear and safe designs like the CANDU plant will become significantly more popular.</p>

<p>Much of the new power brought online will be fueling desalinization and water-reclamation facilities to stabilize the fresh water supply. Fresh water will dominate the news cycle as energy does today.</p>

<h3 id="conclusion">Conclusion</h3>

<p>With all of the changes described above, North America will see a significant effect on the number of low-end jobs. Manufacturing, food and transport industries will be radically changed, jobs moving from many low-skilled positions to a few high-end positions.</p>

<p>This will require thought on how we can re-architect the economy. I think we’ll see concepts like minimum guaranteed income replacing welfare and minimum wage. This is much more difficult to predict than the pace of technology, but we’ll have to do something to ensure that everyone is able to live in the new world we’re building.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Colossal Cave Adventure]]></title>
		<link href="https://grack.com/blog/2012/08/13/colossal-cave-adventure"/>
		<updated>2012-08-13T00:00:00-06:00</updated>
		<id>https://grack.com/blog/2012/08/13/colossal-cave-adventure</id>
		<content type="html"><![CDATA[<p>This is a fun little project I’ve been working on: a port of the Colossal Cave Adventure to the web. The monitor itself is nearly 100% CSS (with the exception of one image for the masking tape/signature and the diffuse reflection of the background).</p>

<p>The interpreter is all Java and compiled to JS via GWT. It can save its state to localStorage right now when you save in-game (although I’d like to automatically persist the state of the engine continuously before I release it).</p>

<p>And, FWIW, the Colossal Cave Adventure is a surprisingly hard game. ﻿</p>

<p><strong>UPDATE</strong>: Source <a href="https://github.com/mmastrac/adventure">is on github</a> and you can <a href="https://grack.com/demos/adventure">play it here</a>.</p>

<p><a class="image standard" href="https://grack.com/assets/2012/08/adventure.jpg"><img src="https://grack.com/_thumbs/01674d09b954a1f32138cf430b9893fd-600-600"></a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[On Google Chromebooks]]></title>
		<link href="https://grack.com/blog/2012/05/30/on-google-chromebooks"/>
		<updated>2012-05-30T00:00:00-06:00</updated>
		<id>https://grack.com/blog/2012/05/30/on-google-chromebooks</id>
		<content type="html"><![CDATA[<p><em>This is a follow-up to <a href="https://grack.com/blog/2011/02/05/a-week-with-a-chromeos-netbook">my week with a ChromeOS netbook</a> post.</em></p>

<p><a class="image floatright" href="https://grack.com/assets/2011/02/cr48box2.jpg"><img src="https://grack.com/_thumbs/2a8ae04b3d2d7668dee038b37e6b3c8a-600-600" align="right" width="200"></a>The Google Chromebook is an interesting product to watch. I’ve been a fan of and using them since the early Cr-48 days. In fact, two Chromebook laptops were in service in our household until just a few weeks ago when the Samsung Chromebook broke (although I hope to repair it soon).</p>

<p>These laptops sit next to our couch in a stack as a set of floater laptops we use for random surfing. If any of us are just looking for a quick bite of information, we generally pull out the Chromebook rather than walking over to the Macbook that sits on our kitchen counter. The Chromebook is also great for our son to use when building LEGO from PDF instructions.</p>

<p>Browsing is far better on the Chromebook than it is on any Android or iOS device I’ve used, hands down. I find the browsing experience to be frustrating on an iPad or my Galaxy 10”, while the Chromebook experience is flawless. The device is basically ready-to-use for browsing as soon as you lift the lid, in contrast to the fair amount of time it takes to get logged into the Macbook (especially if another user has a few applications open in their session).</p>

<p>The hardware itself in the early models was slightly underpowered, but that doesn’t really seem to matter much unless you’re playing a particularly intensive Flash video or HTML5 game. Scrolling is fairly slow on complex sites like Google+ as well, but it’s never been a showstopper. The touchpads have also been hit-and-miss in the early models. For what we use it for, the hardware is pretty decent. I imagine that the next generations will gradually improve on these shortcomings.</p>

<p>What makes these devices a hard sell is the price point. The cheapest Chromebook experience you can get today is the Acer (@ $300). Considering the fact that you are buying a piece of hardware that effectively does less than a laptop, I would find it hard to justify spending that amount if I were looking at hardware today. Even though I prefer to use the Chromebook when surfing over the tablets or the full laptop, I feel like the cost is just too much for a single-purpose device like this.</p>

<p>For Chromebooks to really take off in the home market, I think that a device with the equivalent power to the Samsung Chromebook 5 needs to be on the market at a $199 price point. I could see myself buying them without a second thought at that price. Alternatively, if we saw some sort of Android hybrid integration with the Chromebook, I think that this could radically change the equation and add significant perceived value to the device.</p>

<p>I don’t see the Chromebox being popular in households ever - I believe that we’ll see the decline of the non-portable computer going forward at home. Now, if I were running a business where a large subset of employees could get by with just web access, I would definitely consider rolling these out. The Chromebox looks like it could be a real game changer for business IT costs.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Upcoming Google+ features: hashtag autocomplete, new circle management, and more]]></title>
		<link href="https://grack.com/blog/2011/11/11/upcoming-google-features-hashtag-autocomplete-new-circle-management-and-more"/>
		<updated>2011-11-11T00:00:00-07:00</updated>
		<id>https://grack.com/blog/2011/11/11/upcoming-google-features-hashtag-autocomplete-new-circle-management-and-more</id>
		<content type="html"><![CDATA[<p>I’ve been snooping around the Google+ code a bit and found some more upcoming features.</p>

<p>Hashtags are getting a bit of a boost with auto-completion. When you type the hash character, you’ll see a list of potential auto-completions (this doesn’t appear to be hooked up to any data). When you hit space, it turns into a blue block containing the hashtag, which acts like the blue blocks that contain + mentions:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/01-hashtag.png"><img src="https://grack.com/_thumbs/198f48a154524f7003ae9bf0ddf38ad6-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/02-hashtag.png"><img src="https://grack.com/_thumbs/37d66e243596180ef8c0113b18d4e030-600-600"></a></p>

<p>Circle management looks like it might be dropping the circle visual metaphor. The new interface lists your circles on the left, although this wasn’t working very well, so it’s difficult to say what the final result will look like:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/03-circles.png"><img src="https://grack.com/_thumbs/482291e86a11bb94653be681b19c7636-600-600"></a></p>

<p>The new interface contains two menus: one replaces the existing Relevance drop-down, while the other contains some interesting new menu items. Increase and decrease circle size appear to change the size of the circles on the circle management page. Might be an internal option for the user experience team to eyeball the correct sizing:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/04-circle.png"><img src="https://grack.com/_thumbs/e9b6737565d93943fdd0ac1d20b94b7b-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/05-circle.png"><img src="https://grack.com/_thumbs/36bbe9c12b9b84a922248c1c46b7b50a-600-600"></a></p>

<p>There’s a new “more” dropdown on a profile page that doesn’t seem to do anything, and games may appear in the right sidebar:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/06-more.png"><img src="https://grack.com/_thumbs/d41d1ab2b68d09e8e07bbd970043b974-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/14-games.png"><img src="https://grack.com/_thumbs/321c119925021e09726e808424c470c6-600-600"></a></p>

<p>Photos are getting some tweaks. The photo previews are appearing larger in the photos tab, and there’s a new “Link to this photo” option:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/07-photos.png"><img src="https://grack.com/_thumbs/51df306427c005642182e51705d447dd-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/08-photos.png"><img src="https://grack.com/_thumbs/cf35ba05ebcece3077f8a295a098c950-600-600"></a></p>

<p>There’s a new “Recommendations” link on the left side of your home screen that links to a page that doesn’t exist yet. Clicking on the Recommendations link takes you to a 404 page at <a href="http://plus.google.com/plusones/posts">http://plus.google.com/plusones/posts</a>.</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/09-rec.png"><img src="https://grack.com/_thumbs/f51ded79761edd57ca06def1a0b44f5b-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/10-posts.png"><img src="https://grack.com/_thumbs/e2ee268285bcc7934fbb286c6118b461-600-600"></a></p>

<p>You can now control who can post on your public posts. This might be useful for celebrities, although I’m not really sure who it’s targeted at:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/11-comments.png"><img src="https://grack.com/_thumbs/b30bbf976638713f990b228c2778b41e-600-600"></a></p>

<p>Individual posts are now getting a “Hangout” button. Discuss a post in real-time with others that have seen it!</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/12-hangout.png"><img src="https://grack.com/_thumbs/b1bd8247835638707580b7b8adb8e13f-600-600"></a></p>

<p>You can now mute a person in addition to a single post, and the post sharing dropdown is getting a bit of a makeover with item icons:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/13-mute.png"><img src="https://grack.com/_thumbs/6537a5a083f37cd4dc8bf62241517cb7-600-600"></a><a class="image standard" href="https://grack.com/assets/2011/11/gplus/15-sharing.png"><img src="https://grack.com/_thumbs/d5379396a7777faa6b322780f1021dd5-600-600"></a></p>

<p>I’m not sure if this welcome page was already there, but I haven’t seen this screen before:</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/gplus/16-welcome.png"><img src="https://grack.com/_thumbs/6a887ef4e36dcea7c8c6f98ac4c41bf7-600-600"></a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Five minutes with the Kobo Vox]]></title>
		<link href="https://grack.com/blog/2011/11/05/five-minutes-with-the-kobo-vox"/>
		<updated>2011-11-05T00:00:00-06:00</updated>
		<id>https://grack.com/blog/2011/11/05/five-minutes-with-the-kobo-vox</id>
		<content type="html"><![CDATA[<p><a class="image floatright" href="https://grack.com/assets/2011/11/Kobo_Vox_resize_440x330.png"><img src="https://grack.com/_thumbs/863fd0424a1defa8e717d9e571267b12-600-600" align="right" width="200"></a>Today I had a chance to play with the Canadian equivalent of the Kindle Fire, the Kobo Vox. It’s an Android 2.3 device, which means that it effectively has access to the entire ecosystem of Android apps. What it lacks, unfortunately, is the official Google Market application. It did appear to have access to the Gmail app, which makes the lack of Google’s Android market surprising.</p>

<p>The Vox is a bit lackluster in the graphics department. Full-screen animations like zooms and fades are choppy: 5-10 frames per second. The same animations in the Kobo application on my Galaxy Tab 10 are fluid and smooth. This makes the Kobo Vox feel like a really cheap bit of hardware. It’s not a big deal while reading books in the Kobo application: paging is lightning fast, although it doesn’t have any sort of animation to indicate page flips.</p>

<p>One thing you get with the Vox that you won’t get with the plain Kobo application on other devices is the <a href="http://www.kobobooks.com/kobovox_readinglife">“Kobo Voice” social reading experience</a>. You can annotate passages in books and share them with other readers. I don’t find this to be a big loss. The Vox also offers a way to lay out books in two-page landscape mode, which would be amazing on the Galaxy Tab 10, but feels a bit cramped on the smaller Vox screen.</p>

<p>The Kobo Vox does have a nice screen. The Dell Streak 7” tablet has issues with narrow viewing angles in portrait mode. From what I could tell, the Vox was beautiful in portrait and landscape orientation. The quality of the display feels pretty good.</p>

<p>Based on the five minutes I played with it, I don’t think it’s worth me buying. I’m tempted to look at the Kindle Fire for use in Canada, but I suspect that Amazon’s less-than-perfect support for Amazon services in Canada will make it less of an interesting piece of hardware. If you don’t already have a tablet, however, this might not be a bad device to purchase.</p>

<p>Comparable devices:</p>

<ul>
  <li>Kindle Fire: $200</li>
  <li>Kobo Vox: $200</li>
  <li>Dell Streak 7”: $399 (terrible for reading in portrait!)</li>
  <li>Galaxy Tab 8.9: $400-600 (couldn’t find it for sale in Canada)</li>
  <li>Galaxy Tab 10.1: $649</li>
</ul>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Google +1 Chrome extension tracks your https traffic]]></title>
		<link href="https://grack.com/blog/2011/11/03/google-1-extension-tracks-your-https-traffic"/>
		<updated>2011-11-03T00:00:00-06:00</updated>
		<id>https://grack.com/blog/2011/11/03/google-1-extension-tracks-your-https-traffic</id>
		<content type="html"><![CDATA[<p><strong>EDIT</strong>: In a response to <a href="https://plus.google.com/115459243651688775505/posts/CDiwzBti5G9">this post on Google+</a>, Louis Gray says that he’s notified the team. I’ll update this post as I get more information.</p>

<p>The Google +1 extension for the Chrome browser sends an RPC event to Google for every page you visit, https or not.</p>

<p>I hate to be a downer on cool stuff like this, but I really don’t think this is acceptable. It’s even sending the querystring, which could potentially contain a secure session token. All of the communication to the Google servers happens over https, but I don’t think that excuses this. https:// traffic needs to be off-limits for auto-tracking like this.</p>

<p>I’d be OK if the button allowed you to disable auto-reporting of the current +1 count (this can default to ‘on’), and added a default-off option to show +1 counts for https sites.</p>

<p>Below is a screenshot of the RPC request sent to Google’s RPC endpoint, showing the https URL of a bank’s login URL, complete with query-string.</p>

<p><a class="image standard" href="https://grack.com/assets/2011/11/Screen-Shot-2011-11-03-at-1.49.49-PM.png"><img src="https://grack.com/_thumbs/81109bf4c89498fde41740aad7b4d065-600-600"></a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Automatic file transfer in iTerm2 via ZModem]]></title>
		<link href="https://grack.com/blog/2011/10/26/automatic-file-transfer-in-iterm2-via-zmodem"/>
		<updated>2011-10-26T00:00:00-06:00</updated>
		<id>https://grack.com/blog/2011/10/26/automatic-file-transfer-in-iterm2-via-zmodem</id>
		<content type="html"><![CDATA[<p><a class="image floatright" href="https://grack.com/assets/2011/10/Hayes_Modem.jpg"><img src="https://grack.com/_thumbs/8facf4bac68534a70a6f65c3bcebd3c0-600-600" align="right" width="200"></a><code>scp</code> is a great way to securely transfer files from computer to computer, but wouldn’t it be nice if you could just automatically send files over the existing SSH connection you’ve already opened?</p>

<p>Back in the days of modem-based BBSes and dial-up machine access, file transfers were forced to run over the same TTY as your interaction with the system. A number of different solutions evolved for this, starting with the grandfather of transfer solutions, <a href="http://en.wikipedia.org/wiki/XModem">XModem</a>. Other transfer protocols evolved, some starting from the ground up like <a href="http://en.wikipedia.org/wiki/Kermit_%28protocol%29">Kermit</a>, while <a href="http://en.wikipedia.org/wiki/YModem">YModem</a> and <a href="http://en.wikipedia.org/wiki/ZModem">ZModem</a> build on the foundation of XModem.</p>

<p>The latest version of <a href="http://www.iterm2.com/#/section/home">iTerm 2</a> added support for two features that were very interesting: Triggers, that match a regular expression to a line of text; and co-processes, that can feed input directly into a terminal. With these two features, we can add the ability to stream files to and from any server over an existing ssh session. As ZModem is most modern protocol with wide support (lrzsz is well-supported and packaged on both OSX and Linux), I’ll show you how to use it to automate piggy-backed file uploads and downloads in your iTerm sessions.</p>

<h3 id="setup">Setup</h3>

<p>First of all, install <code>lrzsz</code> via brew. This will install the <code>sz</code> and <code>rz</code> binaries in <code>/usr/local/bin/</code>:</p>

<pre><code>macbook-pro-2:~ matthew$ brew install lrzsz
==&gt; Downloading http://www.ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz
==&gt; ./configure --prefix=/usr/local/Cellar/lrzsz/0.12.20 --mandir=/usr/local/Cellar/lrzsz/0.12.20/share/man
==&gt; make
==&gt; make install
/usr/local/Cellar/lrzsz/0.12.20: 13 files, 376K, built in 21 seconds
</code></pre>

<p>Secondly, grab the scripts from <a href="https://github.com/mmastrac/iterm2-zmodem">my iterm2-zmodem github repo</a>, and save them in <code>/usr/local/bin/</code>.</p>

<p>Next, we’ll add a Trigger to your iTerm 2 profile that will trigger on the signature of the <code>rz</code> and <code>sz</code> commands. The setup for these commands differs based on the iTerm 2 version you have:</p>

<p>Build newer than 1.0.0.20111026</p>

<pre><code>Regular expression: \*\*B0100
    Action: Run Coprocess
    Parameters: /usr/local/bin/iterm2-send-zmodem.sh

    Regular expression: \*\*B00000000000000
    Action: Run Coprocess
    Parameters: /usr/local/bin/iterm2-recv-zmodem.sh
</code></pre>

<p>Build older than 1.0.0.20111026 (only receive supported)</p>

<pre><code>Regular expression: [\$#] rz( -v)?$
    Action: Run Coprocess
    Parameters: /usr/local/bin/iterm2-send-zmodem.sh
</code></pre>

<p>Note: ideally we’d be matching on the ZModem initial packet signature: <code>\*\*\u0018B01</code> in all versions of iTerm 2, but earlier versions of iTerm 2 had a bug that broke this pattern detection in this case. Instead we’re matching against the pattern of the <code>rz</code> command typed at a shell for those older builds.</p>

<h3 id="receiving-files-from-the-server">Receiving files from the server</h3>

<p>To receive a file on your server, type the following at a shell prompt:</p>

<pre><code># rz
</code></pre>

<p>A file-picker dialog will then pop up asking you for the file to send. Once you choose the file to send, it will automatically transfer the file across your existing console session.</p>

<h3 id="sending-files-to-the-server">Sending files to the server</h3>

<p>To send files from your server to your desktop, type the following:</p>

<pre><code># sz file1 file2 file3 /folder/file*
</code></pre>

<p>A folder picker will show up, asking where you want to drop the files. If you send multiple files, they will all appear in this folder.</p>

<h3 id="wrap-up">Wrap-up</h3>

<p>This is a pretty rough first pass at this, but the shell scripts are <a href="https://github.com/mmastrac/iterm2-zmodem">available on github</a> if you’ve got ideas for improvement.</p>

<p>Follow me on Twitter: <a href="http://twitter.com/mmastrac">@mmastrac</a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[On the advancement of science and the useful arts]]></title>
		<link href="https://grack.com/blog/2011/08/24/on-the-advancement-of-science-and-the-useful-arts"/>
		<updated>2011-08-24T00:00:00-06:00</updated>
		<id>https://grack.com/blog/2011/08/24/on-the-advancement-of-science-and-the-useful-arts</id>
		<content type="html"><![CDATA[<p>Apple is quickly burning my goodwill towards with <a href="http://www.engadget.com/2011/08/24/netherlands-judge-rules-that-samsung-galaxy-s-s-ii-violate-appl/">these silly patent fights</a>. Two out of three of the patents were found not to be infringing, while the last one is a software patent that basically describes the functioning of <a href="http://worldwide.espacenet.com/publicationDetails/description?CC=EP&amp;NR=2059868A2&amp;KC=A2&amp;FT=D&amp;date=20090520&amp;DB=&amp;locale=en_EP">a mobile device that deals with photos</a>.</p>

<p>At this point, it’s probably worth pointing out that Apple’s notification bar is <a href="http://androidandme.com/2011/06/news/is-this-real-life-apple-copies-androids-notification-system-and-lock-screen/">pretty much a rip-off</a> of the Android one. And you know what? <strong>I really don’t care</strong>.</p>

<p>Companies <em>should</em> be riffing off each other’s designs and improving them as they do. We’ll get a lot further than if we give one company total control over a single domain. Apple has taken the Android notification bar and improved it, just as Google has done with various iPhone features. Both companies have built their mobile operating systems on the prior art of <em>thousands</em> of other inventions from the last thirty years.</p>

<p>As many people have stated, patents are a monopoly to advance science and the useful arts. They are not a monopoly to advance the profits of any given company, though that may be a side-effect of their existence.</p>

<p>Copyright and trademark law already exist to prevent direct copying of design. Would Apple have released the iPhone in the absence of software patents? <em>Very likely</em>. Would the iPhone/Android rivalry shaped up the same way without software patents? <em>Very likely</em>.<br>
In their current form, software patents have been hindering the progress of computing. With that in mind, I say <em>it’s time for them to go</em>.</p>

<p>Follow me on Twitter: <a href="http://twitter.com/mmastrac">@mmastrac</a></p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[Nearing nanojson v1.0]]></title>
		<link href="https://grack.com/blog/2011/08/08/almost-nanojson-1"/>
		<updated>2011-08-08T00:00:00-06:00</updated>
		<id>https://grack.com/blog/2011/08/08/almost-nanojson-1</id>
		<content type="html"><![CDATA[<p>I’m nearly ready to cut a 1.0 version of nanojson. I spent some time merging the two writer interfaces into a single API.</p>

<pre><code>String json = JsonWriter.string()
  .object()
  .array("a")
    .value(1)
    .value(2)
  .end()
  .value("b", false)
  .value("c", true)
  .end()
.close();
</code></pre>

<p>There’s a new convenience static for quickly converting stuff to a string as well:</p>

<pre><code>String json = JsonWriter.string(object);
</code></pre>

<p>I suspect I may rename the close() method to something that doesn’t infer closing of the underlying stream (maybe finish() or complete()?)</p>

<p>You’ll find it <a href="https://github.com/mmastrac/nanojson">at GitHub here</a>.</p>
]]></content>
	</entry>
	
	
	
	<entry>
		<title type="html"><![CDATA[nanojson API]]></title>
		<link href="https://grack.com/blog/2011/07/21/nanojson-api"/>
		<updated>2011-07-21T00:00:00-06:00</updated>
		<id>https://grack.com/blog/2011/07/21/nanojson-api</id>
		<content type="html"><![CDATA[<p>Found some time tonight to flesh out nanojson’s API a bit more. Going to start replacing all the various JSON.org parsers scattered around production code with this to get a better idea of how the API feels.﻿</p>

<p>You’ll find it <a href="https://github.com/mmastrac/nanojson">at GitHub here</a>.</p>
]]></content>
	</entry>
	
	
</feed>
