<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>forsooth!</title><link href="https://forsooth.org/" rel="alternate"></link><link href="https://forsooth.org/feeds/all.atom.xml" rel="self"></link><id>https://forsooth.org/</id><updated>2019-04-22T00:00:00+02:00</updated><subtitle>By necessity, by proclivity, and by delight, we all quote.</subtitle><entry><title>Partial Bézier Curves</title><link href="https://forsooth.org/posts/partial-bezier-curves" rel="alternate"></link><published>2019-04-22T00:00:00+02:00</published><updated>2019-04-22T00:00:00+02:00</updated><author><name>@or</name></author><id>tag:forsooth.org,2019-04-22:/posts/partial-bezier-curves</id><summary type="html">Render partial quadratic Bézier&amp;nbsp;curves</summary><content type="html">&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;p&gt;I recently worked on some visualization with &lt;code&gt;d3&lt;/code&gt;, rendering a directed graph of nodes with a force simulation. An easy way to render the edges of the graph is to simply draw a straight line, but that’s not very pretty. Instead, a neat trick is to introduce an invisible node inbetween two connected nodes, and then render a &lt;strong&gt;quadratic&lt;/strong&gt; Bézier curve between the nodes, using the invisible node as control point.&lt;/p&gt;
&lt;p&gt;This example shows the curved link between two nodes, without force simulation, the nodes can be dragged around interactively. The nodes are transparent to illustrate the actual ends of the curve.&lt;/p&gt;
&lt;div id="graph-1" style="border: 1px solid #eee"&gt;&lt;/div&gt;
&lt;p&gt;The relevant code for rendering the path of the edges in &lt;code&gt;d3&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight javascript"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;edgeElements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;edgeLayer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".edge"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;edgeElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"edge"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"stroke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"#ddd"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"stroke-width"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// on update&lt;/span&gt;
&lt;span class="nx"&gt;edgeLayer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".edge"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"M"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"Q"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(See &lt;a href="https://www.w3.org/TR/SVG/paths.html"&gt;&lt;span class="caps"&gt;SVG&lt;/span&gt;:path docs&lt;/a&gt; for explanation of the &lt;code&gt;M&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt; commands.)&lt;/p&gt;
&lt;p&gt;This connects the centers of each node, which is great for undirected graphs, but not very useful for directed graphs. Where and how should the arrow be rendered? And how can the curve be rendered only from node edge to node edge? This is particularly important if the nodes are transparent, as above, or have non-circular shapes, for instance based on an &lt;span class="caps"&gt;SVG&lt;/span&gt; pattern fill, a logo, etc..&lt;/p&gt;
&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;
&lt;h3 id="finding-the-touching-points"&gt;Finding the touching points&lt;/h3&gt;
&lt;p&gt;The first step must be finding the touching points of the curve with the rim of the node. The “rim” will be assumed based on the radius of the node, even if the node itself might have an irregular shape, but since I want a little spacing between node and curve anyway, this is sufficient.&lt;/p&gt;
&lt;p&gt;Wikipedia has a more thorough explanation of &lt;a href="https://en.wikipedia.org/wiki/B%C3%A9zier_curve"&gt;Bézier curves&lt;/a&gt;, but for what I’m doing I need this function:&lt;/p&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[ B\colon [0, 1] \Rightarrow \mathbb{R}^2 \]&lt;/span&gt; &lt;span class="math display"&gt;\[ B(t) \, = \, (1 - t)^2 P_0 + 2 (1 - t) t P_1 + t^2 P_2 \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Where &lt;span class="math inline"&gt;\(P_0\)&lt;/span&gt; and &lt;span class="math inline"&gt;\(P_2\)&lt;/span&gt; are the end points of the curve and &lt;span class="math inline"&gt;\(P_1\)&lt;/span&gt; is the control point. It’s easy to see that &lt;span class="math inline"&gt;\(B(0) = P_0\)&lt;/span&gt; and &lt;span class="math inline"&gt;\(B(1) = P_2\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Let’s assume the radius of our node around &lt;span class="math inline"&gt;\(P_0\)&lt;/span&gt; is &lt;span class="math inline"&gt;\(r\)&lt;/span&gt;, then we need to find the smallest &lt;span class="math inline"&gt;\(t\)&lt;/span&gt;, such that &lt;span class="math inline"&gt;\(|B(t) - P_0| = r\)&lt;/span&gt;, i.e. the &lt;span class="math inline"&gt;\(t\)&lt;/span&gt; at which the curve is at a distance of &lt;span class="math inline"&gt;\(r\)&lt;/span&gt; from &lt;span class="math inline"&gt;\(P_0\)&lt;/span&gt; for the first time. In most curves there’ll only be one such point, but just in case the nodes are very close together, perhaps even overlapping, the first one is the point we want. The same can be done from the end.&lt;/p&gt;
&lt;p&gt;I tried to solve this mathematically, but even for quadratic Bézier curves this grows into big expressions and polynomials of 4th degree, so I went with a binary search for a close approximation instead:&lt;/p&gt;
&lt;div class="highlight javascript"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;calculateBezierPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;findProximityPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rSquared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;lastWasLower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;calculateBezierPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;distSquared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastWasLower&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;distSquared&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;rSquared&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;lastWasLower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;lastWasLower&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;distSquared&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;rSquared&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;lastWasLower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.001&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;distSquared&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;rSquared&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the relevant code in &lt;code&gt;d3&lt;/code&gt; to render the path of the edge, which now first calculates the points on the curve close to the node edges and then uses those points as start and end of the curve:&lt;/p&gt;
&lt;div class="highlight javascript"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;edgeLayer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".edge"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;findProximityPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;findProximityPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"M"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"Q"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div id="graph-2" style="border: 1px solid #eee"&gt;&lt;/div&gt;
&lt;p&gt;This works quite well, but it isn’t perfect. Since we use the same control point with different start points, the curve differs quite a bit. The ends also don’t necessarily point towards the center of the nodes anymore, which you can easily see by moving the control point around one of the points.&lt;/p&gt;
&lt;h3 id="adding-an-arrow"&gt;Adding an arrow&lt;/h3&gt;
&lt;p&gt;To illustrate this, below the same example with the original edge included, and including an arrow marker to better see where it points. For that the end’s proximity point must be pushed out a bit further (by the length of the arrow) and the arrow is achieved like this:&lt;/p&gt;
&lt;div class="highlight javascript"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;defs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'svg:defs'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;arrowMarker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"marker"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"arrow"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"markerWidth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"markerHeight"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"refX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"refY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"orient"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"auto"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"markerUnits"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"strokeWidth"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;arrowMarker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"M1,3 L0,5 L6,3 L0,1 z"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"fill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"#ddd"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// applying it to the edges&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;edgeElements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;edgeLayer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".edge"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;edgeElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"edge"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"stroke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"#ddd"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"stroke-width"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"marker-end"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"url(#arrow)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div id="graph-3" style="border: 1px solid #eee"&gt;&lt;/div&gt;
&lt;h3 id="construct-a-partial-curve"&gt;Construct a partial curve&lt;/h3&gt;
&lt;p&gt;Ideally the curve between the two touching points follows the original curve. We know the values &lt;span class="math inline"&gt;\(t_{start}\)&lt;/span&gt; and &lt;span class="math inline"&gt;\(t_{end}\)&lt;/span&gt; for which &lt;span class="math inline"&gt;\(B(t_{start}) = P_{start}\)&lt;/span&gt; and &lt;span class="math inline"&gt;\(B(t_{end}) = P_{end}\)&lt;/span&gt;, so &lt;span class="math inline"&gt;\(B(t)\)&lt;/span&gt; could simply be rendered for &lt;span class="math inline"&gt;\(t \in [t_{start},
t_{end}]\)&lt;/span&gt; instead of &lt;span class="math inline"&gt;\(t \in [0, 1]\)&lt;/span&gt;. Unfortunately &lt;span class="caps"&gt;SVG&lt;/span&gt;’s &lt;code&gt;path&lt;/code&gt; commands don’t support such a feature.&lt;/p&gt;
&lt;p&gt;To achieve the effect nonetheless, we first define a new function &lt;span class="math inline"&gt;\(C\)&lt;/span&gt; which follows &lt;span class="math inline"&gt;\(B\)&lt;/span&gt; along the relevant interval, but itself using the domain &lt;span class="math inline"&gt;\([0, 1]\)&lt;/span&gt;:&lt;/p&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[ C\colon [0, 1] \Rightarrow \mathbb{R}^2 \]&lt;/span&gt; &lt;span class="math display"&gt;\[ C(t) = B(t_{start} + (t_{end} - t_{start}) t) \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We also know the start and end points:&lt;/p&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[ P_{start} = C(0) = B(t_{start}) \]&lt;/span&gt; &lt;span class="math display"&gt;\[ P_{end} = C(1) = B(t_{end}) \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Finally, we want &lt;span class="math inline"&gt;\(C\)&lt;/span&gt; to be a Bézier curve, so it must have the same structure. Calling the control point &lt;span class="math inline"&gt;\(X\)&lt;/span&gt; we have:&lt;/p&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[ C(t) \, = \, (1 - t)^2 P_{start} + 2 (1 - t) t X + t^2 P_{end} \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Putting it all together it is: &lt;span class="math display"&gt;\[ (1 - t)^2 P_{start} + 2 (1 - t) t X + t^2 P_{end} \, = \, \]&lt;/span&gt; &lt;span class="math display"&gt;\[ (1 - (t_{start} + (t_{end} - t_{start}) t))^2 P_0 + \]&lt;/span&gt; &lt;span class="math display"&gt;\[ 2 (1 - (t_{start} + (t_{end} - t_{start}) t)) (t_{start} + \]&lt;/span&gt; &lt;span class="math display"&gt;\[(t_{end} - t_{start}) t) P_1 + (t_{start} + (t_{end} - t_{start}) t)^2 P_2 \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;which means&lt;/p&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[ (1 - t)^2 ((1 - t_{start})^2 P_0 + 2 (1 - t_{start}) t_{start} P_1 + t_{start}^2 P_2) + \]&lt;/span&gt; &lt;span class="math display"&gt;\[ 2 (1 - t) t X + \]&lt;/span&gt; &lt;span class="math display"&gt;\[ t^2 ((1 - t_{end})^2 P_0 + 2 (1 - t_{end}) t_{end} P_1 + t_{end}^2 P_2) \, = \, \]&lt;/span&gt; &lt;span class="math display"&gt;\[ (1 - (t_{start} + (t_{end} - t_{start}) t))^2 P_0 + \]&lt;/span&gt; &lt;span class="math display"&gt;\[ 2 (1 - (t_{start} + (t_{end} - t_{start}) t)) (t_{start} + \]&lt;/span&gt; &lt;span class="math display"&gt;\[(t_{end} - t_{start}) t) P_1 + (t_{start} + (t_{end} - t_{start}) t)^2 P_2 \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;and &lt;code&gt;sympy&lt;/code&gt; helps us with that, yielding:&lt;/p&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[ X \, = \, t_{start} t_{end} (P_0 - 2 P_1 + P_2) + (1 - t_{start} - t_{end}) P_0 + (t_{start} + t_{end}) P_1 \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So finally we can construct a new Bézier curve from &lt;span class="math inline"&gt;\(P_{start}\)&lt;/span&gt; to &lt;span class="math inline"&gt;\(P_{end}\)&lt;/span&gt;, using control point &lt;span class="math inline"&gt;\(X\)&lt;/span&gt;. In code it looks like this:&lt;/p&gt;
&lt;div class="highlight javascript"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;edgeLayer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".edge"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;findProximityPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;findProximityPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;tStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;tEnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;adjustedIntermediate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tStart&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;tEnd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;tStart&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;tEnd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tStart&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tEnd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tStart&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;tEnd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;P2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;tStart&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;tEnd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tStart&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tEnd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;P1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"M"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"Q"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;adjustedIntermediate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;adjustedIntermediate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;","&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For the final result (the wrongly cropped curve included for comparison):&lt;/p&gt;
&lt;div id="graph-4" style="border: 1px solid #eee"&gt;&lt;/div&gt;
</content><category term="d3"></category><category term="svg"></category><category term="maths"></category><category term="visualization"></category></entry><entry><title>Better HTML rendering for spacemail</title><link href="https://forsooth.org/posts/spacemail-better-html-rendering" rel="alternate"></link><published>2017-12-12T00:00:00+02:00</published><updated>2017-12-12T00:00:00+02:00</updated><author><name>@or</name></author><id>tag:forsooth.org,2017-12-12:/posts/spacemail-better-html-rendering</id><summary type="html">Optimize &lt;span class="caps"&gt;HTML&lt;/span&gt; rendering for&amp;nbsp;emails</summary><content type="html">&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;
&lt;p&gt;The rendering of &lt;span class="caps"&gt;HTML&lt;/span&gt; emails is rather ugly, with white/brown backgrounds, totally breaking with the theme. It also is surprisingly slow, especially for long threads and emails containing a lot of quoting in &lt;span class="caps"&gt;HTML&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;
&lt;p&gt;There’s a variable &lt;code&gt;mm-text-html-renderer&lt;/code&gt;, which by default is set to &lt;code&gt;shr&lt;/code&gt;. I prefer using the value &lt;code&gt;w3m&lt;/code&gt;, which uses &lt;code&gt;w3m&lt;/code&gt; and is much faster and prettier. It displays everything in the current theme, highlights links, and displays styles, e.g. strong/bold.&lt;/p&gt;
&lt;p&gt;It also can be set up to honour a fill-column while rendering.&lt;/p&gt;
&lt;h2 id="setup"&gt;Setup&lt;/h2&gt;
&lt;p&gt;As already pointed out: &lt;code&gt;w3m&lt;/code&gt; needs to be installed. Via your favourite packet manager (e.g. &lt;code&gt;pacman&lt;/code&gt;, &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;yum&lt;/code&gt;, &lt;code&gt;brew&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;mm-text-html-renderer&lt;/span&gt; &lt;span class="ss"&gt;'w3m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;w3m-fill-column&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For more information try &lt;code&gt;SPC h d v&lt;/code&gt; and type &lt;code&gt;mm-text-html-renderer&lt;/code&gt; and &lt;code&gt;RET&lt;/code&gt;. There are other renderers available, which might work even better for you.&lt;/p&gt;
</content><category term="spacemacs"></category><category term="email"></category><category term="notmuch"></category></entry><entry><title>PoC||GTFO</title><link href="https://forsooth.org/posts/pocorgtfo" rel="alternate"></link><published>2017-11-08T00:00:00+02:00</published><updated>2017-11-08T00:00:00+02:00</updated><author><name>@or</name></author><id>tag:forsooth.org,2017-11-08:/posts/pocorgtfo</id><summary type="html">Reverse engineering&amp;nbsp;samizdat</summary><content type="html">&lt;h2 id="whats-that"&gt;What’s that?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.alchemistowl.org/pocorgtfo/"&gt;PoC||&lt;span class="caps"&gt;GTFO&lt;/span&gt;&lt;/a&gt; is a &lt;a href="https://en.wikipedia.org/wiki/Samizdat"&gt;samizdat&lt;/a&gt; with a focus on Reverse Engineering and hacking. It is wonderfully put together, with pretty TeX work, old school ads, and illustrations.&lt;/p&gt;
&lt;p&gt;Due to their strict licensing:&lt;/p&gt;
&lt;blockquote class="blockquote"&gt;
&lt;p&gt;&lt;strong&gt;Legal Note&lt;/strong&gt;: We politely ask that you copy this document far and wide.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’ll mirror them here. All issues are available below. Many of these PDFs are polyglots, e.g. they also are valid zip files, and sometimes even executables, the PDFs have more details on that.&lt;/p&gt;
&lt;table class="table table-hover table-striped"&gt;
&lt;tbody&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;file&lt;/td&gt;
&lt;td&gt;sha256sum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo00.pdf"&gt;pocorgtfo00.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;c4d1d1091187b98a9bb28452bc6564a1e8c0ce10d20ba2b4a20f8b7798f7ab64&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo01.pdf"&gt;pocorgtfo01.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a0f93a265d38257a06fd7fd210f73ea9c55a94ac1305c65c0510ada236c2cc88&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo02.pdf"&gt;pocorgtfo02.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;f427e8d95c0ac15abe61d96fb75cfb55df1fd5ac9e713cf968f3602267ca155e&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo03.pdf"&gt;pocorgtfo03.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;7094f5c6a3936e0d0b8f5e42b4d1940413f568e9a3617be0d7d6dc73cb3420e1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo04.pdf"&gt;pocorgtfo04.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1d1567b8ac533cd142a8af560266ca60939fed02e3af1f6fd0816b26473afd01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo05.pdf"&gt;pocorgtfo05.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;9623609a9c0ecd95674e6da3de322baa141f5460cbcb93eeaade22eaf2c80640&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo06.pdf"&gt;pocorgtfo06.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bf4d8846fbbb1071c7ec033004eda8ea8809676fe388db6faa020d781cb8ac26&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo07.pdf"&gt;pocorgtfo07.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;601534f4355c5e0eb292c6dd6edaf5055625d23e0de869f88193606415e6a35f&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo08.pdf"&gt;pocorgtfo08.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;7a942c425f471f99d8cba8da117cc4a53cddb3551e4b16c8b9feae31b5654a33&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo09.pdf"&gt;pocorgtfo09.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;8ad70d4dd0c0f53e8c479d1d573e5a365ea673acafa9fd61fa5231e18502a6ad&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo10.pdf"&gt;pocorgtfo10.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1e350e30383fd332678654b6067fe4b6ea3d25d7f41a24a4c81fe913b295c9de&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo11.pdf"&gt;pocorgtfo11.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;44d56d717c7b3baf7e11aa6624d5a80a90b132a519e61b9682a5f4a635b04c78&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo12.pdf"&gt;pocorgtfo12.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;441216e475e69564192f2121daa5dd465835072718366b75b08b9272ff9cf08b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo13.pdf"&gt;pocorgtfo13.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;c881c67557af52864654791a2a494f329a2fa397236bf0e961508f0769b0a3f5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo14.pdf"&gt;pocorgtfo14.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b9db617dcc146cc99f4379b3162a35818d884bf4032ab854b6ec00b5ec98138d&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo15.pdf"&gt;pocorgtfo15.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;c9b3f5026640efae12d75e62868931e2b2b5ad98a9b858408266ac5c35815bf4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo16.pdf"&gt;pocorgtfo16.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10f0cb977f03824737a413079ded14b237b7ee155a5397e804586ab7151ed0a3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo17.pdf"&gt;pocorgtfo17.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;40b8985521e671b59c305d2f5512f31b95f1e8c59b9c05ad2ca6413a99d59c97&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo18.pdf"&gt;pocorgtfo18.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cd1e5a8f9fdda3a950556ad77db706ab8a01c97662e79c46d417e0e7858aa742&lt;/code&gt; or &lt;code&gt;f427637767d7aea764e0f2045ea4de86bbf5410a43535e70285add347047b283&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;&lt;a href="/pocorgtfo/pocorgtfo19.pdf"&gt;pocorgtfo19.pdf&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;891b6c4e0cc8f88af2b8c2467c1558b806d2f21be4c7518e7833c27885713464&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="pythonruby-polyglot"&gt;Python/Ruby Polyglot&lt;/h2&gt;
&lt;p&gt;It also inspired me to play around with polyglots a bit. Albeit nowhere near as clever as the things I’ve read in the issues already, I wanted to write a script that can be run with Python and Ruby. I wanted the results to differ meaningfully, and try to exploit as many tricks as possible to actually make both interpreters run the same lines of code, rather than doing some eval tricks or whatever.&lt;/p&gt;
&lt;p&gt;I came up with this script, which encrypts when run with Python3 and decrypts when run with Ruby2, I explicitly disabled syntax highlighting, so it isn’t so obvious what’s going on:&lt;/p&gt;
&lt;div class="highlight text"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;key = """PoC||GTFO"
def read(*) STDIN.read.chars end
def ord(x) x.ord end
"""
import sys
begin, read, STDOUT, end = \
__name__, sys.stdin.read(), sys.stdout, sys.exit
#"

i = 0
for c in read \
    :begin; \
    v = (i % 2) * 2 - 1 and 1 - 2 * (i % 2); \
    STDOUT.write("%c" % ((256 + ord(c) + v * ord(key[i % 9])) &amp;amp; 0xff)); \
    i += 1; \
end
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running it encrypts &lt;code&gt;stdin&lt;/code&gt; to &lt;code&gt;stdout&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight text"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;% cat &amp;gt; input &amp;lt;&amp;lt;EOF
Olympian bards who sung
Divine ideas below,
Which always find us young
And always keep us so.
EOF

% &amp;lt;input python polyglot | hexdump -C
00000000  c3 bf c3 bd 36 c3 b1 c3  b4 22 0d 28 c3 91 12 c3  |....6....".(....|
00000010  b2 2f c3 a8 c3 b7 c3 99  23 22 20 c3 90 04 32 c3  |./......#" ...2.|
00000020  b2 c3 ab c3 83 c3 b0 23  27 19 c3 bf 22 c2 a4 c3  |.......#'..."...|
00000030  ad 1d 11 1b 24 c3 90 c3  b3 22 c3 b0 c3 b3 30 c3  |....$...."....0.|
00000040  98 c3 84 08 18 c3 ba 20  c3 ac c2 a4 1a 18 31 12  |....... ......1.|
00000050  29 04 c3 9d c3 aa c3 ad  27 10 c3 9a 26 23 c2 b1  |).......'...&amp;amp;#..|
00000060  36 c3 b3 c3 b9 27 13 c3  84 c3 b2 1e c3 b5 c3 9d  |6....'..........|
00000070  c3 a5 c3 b0 30 0d 33 24  c3 90 c3 bc 22 c3 a9 c3  |....0.3$...."...|
00000080  b4 c3 99 21 2d c3 91 23  00 c3 ab c2 8e           |...!-..#.....|
0000008d
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Python cannot decrypt it:&lt;/p&gt;
&lt;div class="highlight text"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;% &amp;lt;input python polyglot | python polyglot | hexdump -C
00000000  c2 af c2 8e c3 b3 75 78  c3 9b c2 b9 c3 a2 c2 82  |......ux........|
00000010  c3 82 c2 83 c3 ac 6c 7b  c2 92 c3 8f c3 9c c3 91  |......l{........|
00000020  c2 80 c2 95 c3 af 76 6f  7c c2 9c c3 9d c3 98 c3  |......vo|.......|
00000030  89 c2 90 c3 9f 28 71 c3  96 c2 bd c3 95 c3 95 c2  |.....(q.........|
00000040  80 c2 84 c3 9f 74 77 c3  a9 c2 84 7e c2 b9 c3 88  |.....tw....~....|
00000050  c2 8b c3 9d 70 28 c3 93  c3 84 c3 ab c3 83 c3 99  |....p(..........|
00000060  c2 95 c2 9a 6e 71 c3 a0  c2 bc c2 94 c3 97 c3 93  |....nq..........|
00000070  42 c3 b3 77 7d c3 a0 c2  bf 7e c2 a3 c3 8e c2 86  |B..w}....~......|
00000080  c2 9a 69 74 c3 a9 c2 b9  c3 ad c3 95 c2 80 c2 8d  |..it............|
00000090  c3 9f 6d 78 c2 92 c3 8d  c3 a7 c2 82 c3 93 c2 91  |..mx............|
000000a0  c2 a8 12                                          |...|
000000a3
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But Ruby can:&lt;/p&gt;
&lt;div class="highlight bash"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;% &amp;lt;input python polyglot &lt;span class="p"&gt;|&lt;/span&gt; ruby polyglot
Olympian bards who sung
Divine ideas below,
Which always find us young
And always keep us so.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the other way around:&lt;/p&gt;
&lt;div class="highlight bash"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;% &amp;lt;input ruby polyglot &lt;span class="p"&gt;|&lt;/span&gt; python polyglot
Olympian bards who sung
Divine ideas below,
Which always find us young
And always keep us so.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Current Python/Ruby versions:&lt;/p&gt;
&lt;div class="highlight text"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;% python --version
Python 3.6.3

% ruby --version
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux]
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="how-does-it-work"&gt;How does it work?&lt;/h3&gt;
&lt;p&gt;I won’t go into detail too much. It’s not a very complicated script, but the main tricks employed are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ruby doesn’t have &lt;code&gt;​"""​&lt;/code&gt; quotes&lt;/li&gt;
&lt;li&gt;Ruby doesn’t require parentheses for function calls&lt;/li&gt;
&lt;li&gt;Python has different block syntax&lt;/li&gt;
&lt;li&gt;Ruby has silly operator precedence&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are three tricks in there that are not immediately obvious, I think, but I won’t spoil any furher.&lt;/p&gt;
&lt;p&gt;The main trick with the &lt;code&gt;​"""​&lt;/code&gt; quotation could be used to write two entirely separate scripts, of course, but that’d be rather boring, so I only used it to get a foot in the door, setting up some symbols I couldn’t easily write around.&lt;/p&gt;
</content><category term="hack"></category><category term="reverse-engineering"></category></entry><entry><title>Email in spacemacs</title><link href="https://forsooth.org/posts/email-in-spacemacs" rel="alternate"></link><published>2017-10-22T00:00:00+02:00</published><updated>2017-10-22T00:00:00+02:00</updated><author><name>@or</name></author><id>tag:forsooth.org,2017-10-22:/posts/email-in-spacemacs</id><summary type="html">Manage, read, write, send emails in&amp;nbsp;spacemacs</summary><content type="html">&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Email is tedious. Especially at work I get hundreds of emails every day, which need to be managed somehow. A lot of those emails are noise, and ideally I’d only ever have to worry about emails that are signal.&lt;/p&gt;
&lt;p&gt;Additionally, writing email requires a good editor with vim bindings (duh!), spacemacs delivers. Navigating, tagging, and searching emails with modal keybindings also makes dealing with them less annoying.&lt;/p&gt;
&lt;p&gt;This documents my setup, which uses &lt;a href="https://github.com/or/spacemail"&gt;spacemail&lt;/a&gt;, &lt;code&gt;isync&lt;/code&gt;, &lt;code&gt;msmtp&lt;/code&gt;, and &lt;code&gt;notmuch&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="setup"&gt;Setup&lt;/h2&gt;
&lt;h3 id="isyncmbsync"&gt;isync/mbsync&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://isync.sourceforge.net/"&gt;isync&lt;/a&gt; is a command line tool that syncs a remote &lt;span class="caps"&gt;IMAP&lt;/span&gt; account and a local mail directory. I simply run it periodically to poll for new emails. &lt;a href="https://github.com/or/isync"&gt;My fork&lt;/a&gt; supports the macOS Keychain for password retrieval.&lt;/p&gt;
&lt;p&gt;My &lt;code&gt;~/.mbsyncrc&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class="highlight conf"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;IMAPAccount forsooth
Host imap.forsooth.org
User or
KeychainName &amp;lt;KeychainName&amp;gt;
KeychainAccount &amp;lt;KeychainAccount&amp;gt;
SSLType IMAPS
AuthMechs LOGIN

IMAPStore forsooth-remote
Account forsooth

MaildirStore forsooth-local
Subfolders Verbatim
# The trailing "/" is important
Path ~/Mail/or@forsooth.com/
Inbox ~/Mail/or@forsooth.com/INBOX/

Channel forsooth
Master :forsooth-remote:
Slave :forsooth-local:
Patterns "INBOX"

Create Slave
SyncState *
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This syncs everything in the folder “&lt;span class="caps"&gt;INBOX&lt;/span&gt;”. I leave everything serverside in that folder, because it avoids moving emails around physically and syncing back and forth with &lt;span class="caps"&gt;IMAP&lt;/span&gt;. All the tagging is done locally via &lt;code&gt;notmuch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In order to sync multiple folders, the list can be extended to include them, it also supports regular expressions. Either way the Calendar folder of Exchange accounts should be ignored, as Exchange does some non-&lt;span class="caps"&gt;RFC&lt;/span&gt; things that might break the sync (at least that used to happen to me with &lt;code&gt;offlineimap&lt;/code&gt;, I haven’t seen it with &lt;code&gt;mbsync&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;For my work account I also require a specific &lt;span class="caps"&gt;SSL&lt;/span&gt; certificate for the handshake, and the auth configuration differs a little.&lt;/p&gt;
&lt;div class="highlight conf"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;CertificateFile "/usr/local/etc/openssl/certs/some-authority.pem"
&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Credentials via macOS Keychain (recommended)&lt;/p&gt;
&lt;p&gt;My config uses &lt;code&gt;KeychainName&lt;/code&gt; and &lt;code&gt;KeychainAccount&lt;/code&gt; to retrieve the password from the macOS Keychain. This requires Keychain support added in my fork, see above, until it is merged upstream (perhaps).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Credentials via &lt;span class="caps"&gt;GPG&lt;/span&gt; (discouraged)&lt;/p&gt;
&lt;p&gt;An alternative to the Keychain is retrieving the password for the account from &lt;code&gt;~/.authinfo.gpg&lt;/code&gt;, an encrypted file containing login information for &lt;span class="caps"&gt;SMTP&lt;/span&gt; and &lt;span class="caps"&gt;IMAP&lt;/span&gt;:&lt;/p&gt;
&lt;div class="highlight conf"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;machine imap.forsooth.org login or@forsooth.org port 465 password &amp;lt;hunter2&amp;gt;
machine imap.forsooth.org login or@forsooth.org port 993 password &amp;lt;hunter2&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In that case you’d have to set a password command like this:&lt;/p&gt;
&lt;div class="highlight conf"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;PassCmd "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.authinfo.gpg"
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that anyone can do this, if they have access to your machine while you are logged in, if you use gpg-agent to avoid constant password prompts. The Keychain method is more secure.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="migrate-from-offlineimap"&gt;Migrate from offlineimap&lt;/h3&gt;
&lt;p&gt;If you started with offlineimap and want to switch to &lt;code&gt;mbsync&lt;/code&gt;, then that’s easy, just follow the steps outlined &lt;a href="https://github.com/or/spacemail#migrate-from-offlineimap"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="notmuch"&gt;notmuch&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://notmuchmail.org/"&gt;notmuch&lt;/a&gt; processes a local mail directory, building a database that tags and indexes all mails for text searches.&lt;/p&gt;
&lt;p&gt;My &lt;code&gt;~/.notmuch-config&lt;/code&gt; is given below, each setting is described in detail in the notmuch documentation and the template for that file.&lt;/p&gt;
&lt;div class="highlight conf"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;[database]&lt;/span&gt;
&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/or/Mail&lt;/span&gt;

&lt;span class="k"&gt;[user]&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;
&lt;span class="na"&gt;primary_email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;or@forsooth.org&lt;/span&gt;

&lt;span class="k"&gt;[new]&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;unread;inbox;new;&lt;/span&gt;
&lt;span class="na"&gt;ignore&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;

&lt;span class="k"&gt;[search]&lt;/span&gt;
&lt;span class="na"&gt;exclude_tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;deleted;spam;&lt;/span&gt;

&lt;span class="k"&gt;[maildir]&lt;/span&gt;
&lt;span class="na"&gt;synchronize_flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;

&lt;span class="k"&gt;[crypto]&lt;/span&gt;
&lt;span class="na"&gt;gpg_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;gpg&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Importantly there is the setup of the user that sends the email and the tags new mail gets automatically.&lt;/p&gt;
&lt;p&gt;Here is the rough structure of the script to process new email, ideally running after offlineimap syncs the mail.&lt;/p&gt;
&lt;div class="highlight bash"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# find out how many threads are unread before the sync&lt;/span&gt;
&lt;span class="nv"&gt;previous_unread_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;notmuch count --output&lt;span class="o"&gt;=&lt;/span&gt;threads tag:unread&lt;span class="k"&gt;)&lt;/span&gt;
notmuch new

&lt;span class="c1"&gt;# count new and unread email after the sync&lt;/span&gt;
&lt;span class="nv"&gt;new_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;notmuch count tag:new&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;unread_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;notmuch count --output&lt;span class="o"&gt;=&lt;/span&gt;threads tag:unread&lt;span class="k"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# if something changed...&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$new_count&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -gt &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$unread_count&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -gt &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$unread_count&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -ne &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$previous_unread_count&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c1"&gt;# use $new_count and $unread_count for some notification, omitted here&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c1"&gt;# remove the "new" tag from all emails that have it&lt;/span&gt;
notmuch tag -new tag:new
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="tagging-rules"&gt;tagging rules&lt;/h3&gt;
&lt;p&gt;The main script containing all the rules is &lt;code&gt;~/Mail/.notmuch/hooks/post-new&lt;/code&gt;, which may look like this:&lt;/p&gt;
&lt;div class="highlight bash"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;notmuch tag +sent folder:sent
notmuch tag +draft folder:drafts

notmuch tag +me tag:new to:or@forsooth.org
notmuch tag +cron tag:new from:&lt;span class="s2"&gt;"Cron Daemon"&lt;/span&gt;
notmuch tag +invitation-response tag:new &lt;span class="s1"&gt;'vcalendar AND (subject:"accepted" OR subject:"declined" OR subject:"tentative")'&lt;/span&gt;
notmuch tag +ticket tag:new &lt;span class="s1"&gt;'subject:ticket'&lt;/span&gt;
notmuch tag +mailing-list tag:new some-topic@mailinglist.com
notmuch tag +build tag:new from:build-tools@some-service.com
notmuch tag +review tag:new subject:&lt;span class="s2"&gt;"Code Review"&lt;/span&gt;
notmuch tag +cake tag:new cake

notmuch tag +noise -inbox -unread tag:new AND tag:build AND NOT tag:me AND &lt;span class="s2"&gt;"successfully"&lt;/span&gt;
notmuch tag +noise -inbox -unread tag:new AND tag:invitation-response
notmuch tag +noise -inbox -unread tag:new AND tag:cron
notmuch tag +noise -inbox -unread tag:new AND tag:review AND NOT tag:me
notmuch tag -inbox tag:new AND tag:mailing-list
notmuch tag -inbox -unread from:or@forsooth.org AND NOT to:or@forsooth.org

notmuch tag +muted &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;notmuch search --output&lt;span class="o"&gt;=&lt;/span&gt;threads tag:muted&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
notmuch tag +noise -inbox -unread tag:new AND tag:muted

notmuch tag -unread -inbox tag:new AND tag:sent

notmuch tag +signal tag:inbox
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a normal bash script, which allows some pretty cool rules that’d be hard or impossible to apply in the usual email clients.&lt;/p&gt;
&lt;p&gt;In the example config I always filter for mails with the tag &lt;code&gt;new&lt;/code&gt;, which makes the processing much faster. Additional tags are applied based on several rules, which identify them as coming from cronjobs or a build service. Many such emails don’t have to be read, so they get the &lt;code&gt;inbox&lt;/code&gt; tag removed right away. I also give them a &lt;code&gt;noise&lt;/code&gt; tag and the remaining emails a &lt;code&gt;signal&lt;/code&gt; tag for some statistics later on.&lt;/p&gt;
&lt;p&gt;You may wonder why &lt;code&gt;inbox&lt;/code&gt; and &lt;code&gt;unread&lt;/code&gt; tags are used in the way they are. I usually filter for &lt;code&gt;tag:inbox AND tag:unread&lt;/code&gt; in spacemacs, as you’ll see in the next section, but they both serve a different purpose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;inbox - the email is in the inbox and probably needs some action&lt;/li&gt;
&lt;li&gt;unread - the email is worth looking at but hasn’t been read yet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An example is the &lt;code&gt;mailing-list&lt;/code&gt; tag, which keeps an email’s &lt;code&gt;unread&lt;/code&gt; tag, but removes &lt;code&gt;inbox&lt;/code&gt;, because usually there’s a lot of traffic and I just read through them, without expecting each of them to require a response or work.&lt;/p&gt;
&lt;p&gt;Anything with both tags will show up in the inbox, after reading it will lose the &lt;code&gt;unread&lt;/code&gt; tag, but remain in the &lt;code&gt;inbox&lt;/code&gt; until it is archived explicitly.&lt;/p&gt;
&lt;p&gt;Note that any email in a thread given the tag &lt;code&gt;muted&lt;/code&gt; will also get muted and removed from &lt;code&gt;inbox&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another example of how this scripting can do a bit more than just tagging is the following block, which pages me whenever an email mentions cake in the office.&lt;/p&gt;
&lt;div class="highlight bash"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;  &lt;span class="nv"&gt;cake_query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"tag:new AND tag:cake AND tag:unread AND NOT from:or@forsooth.org"&lt;/span&gt;
  &lt;span class="nv"&gt;num_cake&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;notmuch search &lt;span class="nv"&gt;$cake_query&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; wc -l &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$num_cake&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nv"&gt;cake_email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/tmp/cake_email.txt"&lt;/span&gt;
      cat  &amp;gt; &lt;span class="nv"&gt;$cake_email&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF&lt;/span&gt;
&lt;span class="s"&gt;From: pager@forsooth.org&lt;/span&gt;
&lt;span class="s"&gt;To: pager@forsooth.org&lt;/span&gt;
&lt;span class="s"&gt;Subject: "${num_cake}x" cake!&lt;/span&gt;

&lt;span class="s"&gt;There's cake!&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
      sendmail -t &amp;lt; &lt;span class="nv"&gt;$cake_email&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="msmtp"&gt;msmtp&lt;/h3&gt;
&lt;p&gt;In order to send emails via &lt;span class="caps"&gt;SMTP&lt;/span&gt;, I now use &lt;a href="https://marlam.de/msmtp/"&gt;msmtp&lt;/a&gt;, which can act as a &lt;code&gt;sendmail&lt;/code&gt; replacement but sends via an &lt;span class="caps"&gt;SMTP&lt;/span&gt; server. Previously I set up spacemacs to send via &lt;span class="caps"&gt;SMTP&lt;/span&gt;, but that required the &lt;code&gt;.authinfo.gpg&lt;/code&gt; method above to retrieve the password. I &lt;a href="https://github.com/or/msmtp-mirror"&gt;forked msmtp&lt;/a&gt; to also support macOS Keychain access.&lt;/p&gt;
&lt;p&gt;My &lt;code&gt;~/.msmtprc&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class="highlight conf"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;defaults
tls on
# might need this for your server
# tls_trust_file /usr/local/etc/openssl/certs/some-authority.pem

account or
host smtp.forsooth.org
from or@forsooth.org
auth on
user or
keychain_name &amp;lt;KeychainName&amp;gt;
keychain_account &amp;lt;KeychainAccount&amp;gt;

account default : or
&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Credentials via macOS Keychain (recommended)&lt;/p&gt;
&lt;p&gt;Just like in the &lt;code&gt;mbsync&lt;/code&gt; configuration, this specifies a &lt;code&gt;KeychainName&lt;/code&gt; and &lt;code&gt;KeychainAccount&lt;/code&gt; to look up the password in the macOS Keychain. This is currently requires my fork, see above, but hopefully it can be merged upstream.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Credentials via &lt;span class="caps"&gt;GPG&lt;/span&gt; (discouraged)&lt;/p&gt;
&lt;p&gt;Again, the password can be read from &lt;code&gt;.authinfo.gpg&lt;/code&gt; instead. The configuration would look like this:&lt;/p&gt;
&lt;div class="highlight conf"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;passwordeval "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.authinfo.gpg"
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But as mentioned above, this allows anyone with access to an unlocked machine to run the command and to retrieve your password. The Keychain method is more secure.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="spacemacs"&gt;spacemacs&lt;/h3&gt;
&lt;p&gt;Finally, we need a way to read and write emails. This is where spacemacs comes in.&lt;/p&gt;
&lt;p&gt;With a small layer defined in &lt;a href="https://github.com/or/spacemail/blob/master/lib/spacemail/packages.el"&gt;~/.emacs.d/private/layers/spacemail/packages.el&lt;/a&gt; my &lt;code&gt;.spacemacs&lt;/code&gt; config contains:&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;dotspacemacs/layers&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;;; ...&lt;/span&gt;
  &lt;span class="nv"&gt;dotspacemacs-configuration-layer-path&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"~/.emacs.d/private/layers/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;dotspacemacs-configuration-layers&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="c1"&gt;;; ...&lt;/span&gt;
                                      &lt;span class="nv"&gt;spacemail&lt;/span&gt;
                                      &lt;span class="c1"&gt;;; ...&lt;/span&gt;
                                      &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;;; ...&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;dotspacemacs/user-config&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;;; ...&lt;/span&gt;
  &lt;span class="c1"&gt;;; use msmtp as a sendmail replacement to send mails&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;message-send-mail-function&lt;/span&gt; &lt;span class="ss"&gt;'message-send-mail-with-sendmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;sendmail-program&lt;/span&gt; &lt;span class="s"&gt;"/usr/local/bin/msmtp"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;;; get the "From:" address from the envelope Emacs generates&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;message-sendmail-envelope-from&lt;/span&gt; &lt;span class="ss"&gt;'header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;;; ...&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that is it. In the package file above there are several shortcuts set up. Most importantly &lt;code&gt;SPC a m i&lt;/code&gt; for inbox/unread mail and &lt;code&gt;SPC a m n&lt;/code&gt; for new mail.&lt;/p&gt;
&lt;p&gt;Once in a mail listing useful shortcuts are (evil mode):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;h&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, &lt;code&gt;k&lt;/code&gt;, &lt;code&gt;l&lt;/code&gt; navigate&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RET&lt;/code&gt; open mail on cursor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt; search via filter, e.g. &lt;code&gt;tag:build&lt;/code&gt;, &lt;code&gt;cake AND NOT tag:me&lt;/code&gt;, &lt;code&gt;hey there&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt; search in buffer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t&lt;/code&gt; tag mail on cursor; use -&amp;lt;tag&amp;gt; or +&amp;lt;tag&amp;gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Z&lt;/code&gt; to switch to tree view&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt; respond to sender&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R&lt;/code&gt; respond to all&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And now all your vim bindings and spacemacs features will work when writing emails, which is much more nicer than some typical TextWidget.&lt;/p&gt;
&lt;p&gt;For instance, you can format paragraphs quickly and wrap them at the proper width, including quoted text, which can just be selected with &lt;code&gt;V&lt;/code&gt; and reformated with &lt;code&gt;gq&lt;/code&gt;, while keeping the &lt;code&gt;&amp;gt;&lt;/code&gt; prefix correctly at the beginning of each line.&lt;/p&gt;
&lt;p&gt;Last but not least you can take org-mode links to emails! Inside an email just hit &lt;code&gt;SPC a o l&lt;/code&gt; to store a link (this is not specific for the emails, it works in other files as well) and insert it in an org-mode document via &lt;code&gt;​, i l&lt;/code&gt;. This is very nice to make TODOs to respond to specific emails, or attach an important thread to a projet or task.&lt;/p&gt;
</content><category term="spacemacs"></category><category term="notmuch"></category><category term="email"></category><category term="offlineimap"></category></entry><entry><title>Ignore directories in projectile</title><link href="https://forsooth.org/posts/projectile-ignore-directories" rel="alternate"></link><published>2017-10-10T00:00:00+02:00</published><updated>2017-10-10T00:00:00+02:00</updated><author><name>@or</name></author><id>tag:forsooth.org,2017-10-10:/posts/projectile-ignore-directories</id><summary type="html">Ignore directories like .git in projectile&amp;nbsp;helm</summary><content type="html">&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;
&lt;p&gt;Putting a &lt;code&gt;.projectile&lt;/code&gt; into a directory is enough to make it a project root in spacemacs, making it easy to search the entire directory and list its files.&lt;/p&gt;
&lt;p&gt;Listing files in a project is easily done with &lt;code&gt;SPC p f&lt;/code&gt;. There is a &lt;code&gt;native&lt;/code&gt; mode and an &lt;code&gt;alien&lt;/code&gt; mode, the former uses Emacs code to do the file listing, the latter uses external programs. The default is &lt;code&gt;alien&lt;/code&gt; and usually that’s fine and much faster. It will use &lt;code&gt;git&lt;/code&gt; inside a git repository, &lt;code&gt;find&lt;/code&gt; when there’s just a &lt;code&gt;.projectile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;See the &lt;a href="http://batsov.com/projectile/"&gt;projectile documentation&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;However, if you have projects, like me, that have several subdirectories that contain git repositories, like so:&lt;/p&gt;
&lt;div class="highlight example"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;.
└── src
    ├── repo1
    │   └── .git
    ├── repo2
    │   └── .git
    └── repo3
        └── .git
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;then projectile cannot use &lt;code&gt;git&lt;/code&gt; to list files, as it would, if the root were a git repository. It uses &lt;code&gt;find&lt;/code&gt; and with that it also lists all &lt;code&gt;.git&lt;/code&gt; directories. Adding “.git” to &lt;code&gt;.projectile&lt;/code&gt; or &lt;code&gt;projectile-globally-ignored-directories&lt;/code&gt; doesn’t help in this case. At least I couldn’t make it work.&lt;/p&gt;
&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;
&lt;p&gt;So I ended up just adjusting the &lt;code&gt;find&lt;/code&gt; command projectile uses.&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;projectile-generic-command&lt;/span&gt;
  &lt;span class="s"&gt;"find . -type f ! -ipath '.git*' ! -ipath '*/.git*' ! -ipath '*/build/*' -print0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That also hides files in &lt;code&gt;build&lt;/code&gt; subdirectories. And the file list becomes much more manageable.&lt;/p&gt;
</content><category term="spacemacs"></category><category term="helm"></category></entry><entry><title>Custom TODOs in org-mode</title><link href="https://forsooth.org/posts/org-mode-custom-todos" rel="alternate"></link><published>2017-10-08T00:00:00+02:00</published><updated>2017-10-08T00:00:00+02:00</updated><author><name>@or</name></author><id>tag:forsooth.org,2017-10-08:/posts/org-mode-custom-todos</id><summary type="html">Configuring cycles of &lt;span class="caps"&gt;TODO&lt;/span&gt;&amp;nbsp;keywords</summary><content type="html">&lt;h2 id="setup"&gt;Setup&lt;/h2&gt;
&lt;p&gt;It’s easy to add your own &lt;code&gt;TODO&lt;/code&gt; keywords to your &lt;code&gt;org-mode&lt;/code&gt; configuration, you can cycle through them with &lt;code&gt;S-&amp;lt;left&amp;gt;&lt;/code&gt; and &lt;code&gt;S-&amp;lt;right&amp;gt;&lt;/code&gt; or select them with &lt;code&gt;t&lt;/code&gt;, if you use &lt;code&gt;evil&lt;/code&gt; bindings.&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;org-todo-keywords&lt;/span&gt;
      &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;sequence&lt;/span&gt; &lt;span class="s"&gt;"TODO(t!)"&lt;/span&gt; &lt;span class="s"&gt;"WAIT(w!)"&lt;/span&gt; &lt;span class="s"&gt;"|"&lt;/span&gt; &lt;span class="s"&gt;"DONE(d)"&lt;/span&gt; &lt;span class="s"&gt;"CANCELLED(c)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;sequence&lt;/span&gt; &lt;span class="s"&gt;"GOAL(g)"&lt;/span&gt; &lt;span class="s"&gt;"|"&lt;/span&gt; &lt;span class="s"&gt;"ACCOMPLISHED(a)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;sequence&lt;/span&gt; &lt;span class="s"&gt;"READ(r)"&lt;/span&gt; &lt;span class="s"&gt;"|"&lt;/span&gt; &lt;span class="s"&gt;"DONE(d)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;sequence&lt;/span&gt; &lt;span class="s"&gt;"WATCH(W)"&lt;/span&gt; &lt;span class="s"&gt;"|"&lt;/span&gt; &lt;span class="s"&gt;"DONE(d)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All stated before a vertical bar &lt;code&gt;|&lt;/code&gt; are states that still require some action, all states after it indicate the item no longer requires action, i.e. they are “done” states.&lt;/p&gt;
&lt;p&gt;The letters in parentheses are the shortcuts you can use to select them after pressing &lt;code&gt;t&lt;/code&gt;, and the &lt;code&gt;!&lt;/code&gt; adds a log entry whenever that state is entered. For example, the task below was set to &lt;code&gt;WAIT&lt;/code&gt; and a bit later it became a &lt;code&gt;TODO&lt;/code&gt; again. Certainly not needed for every state change, but I like it for those two, because a task might go through these states several times.&lt;/p&gt;
&lt;div class="highlight org"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;* &lt;/span&gt;&lt;span class="kd"&gt;TODO&lt;/span&gt;&lt;span class="kn"&gt; Do something&lt;/span&gt;
&lt;span class="k"&gt;- &lt;/span&gt;State "TODO"       from "WAIT"       &lt;span class="vc"&gt;[2017-10-08 Sun 13:53]&lt;/span&gt;
&lt;span class="k"&gt;- &lt;/span&gt;State "WAIT"       from "TODO"       &lt;span class="vc"&gt;[2017-10-08 Sun 13:31]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="configure-style"&gt;Configure style&lt;/h2&gt;
&lt;p&gt;By default all active &lt;code&gt;TODOs&lt;/code&gt; are displayed in the same style as &lt;code&gt;TODO&lt;/code&gt; itself, all inactive ones are displayed in the style of &lt;code&gt;DONE&lt;/code&gt;. If you want some visual clews to make it more obvious at a quick glance at your todo list, then you can configure each keyword to your heart’s content.&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;org-todo-keyword-faces&lt;/span&gt;
      &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;"WAIT"&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;org-warning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CANCELLED"&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:foreground&lt;/span&gt; &lt;span class="s"&gt;"#657700"&lt;/span&gt; &lt;span class="ss"&gt;:weight&lt;/span&gt; &lt;span class="nv"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here I simply used the &lt;code&gt;org-warning&lt;/code&gt; face for &lt;code&gt;WAIT&lt;/code&gt;, because it works well. For &lt;code&gt;CANCELLED&lt;/code&gt; I wanted something very like &lt;code&gt;DONE&lt;/code&gt;, but somewhat faded to set it apart from &lt;code&gt;DONE&lt;/code&gt; tasks.&lt;/p&gt;
&lt;h2 id="define-clock-stopping-states"&gt;Define clock-stopping states&lt;/h2&gt;
&lt;p&gt;Changing to &lt;code&gt;DONE&lt;/code&gt; (or any other closing state) while clocked into a &lt;code&gt;TODO&lt;/code&gt;&lt;span class="quo"&gt;‘&lt;/span&gt;s heading will automatically clock out of that heading. However, some states might not close the &lt;code&gt;TODO&lt;/code&gt; and still should result in a clock out. For instance, in my setup that’s the state &lt;code&gt;WAIT&lt;/code&gt;. Luckily this sort of thing is supported as well, you can provide a list of states that end a clock:&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;org-clock-out-when-done&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DONE"&lt;/span&gt; &lt;span class="s"&gt;"WAIT"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="avoid-certain-states-as-default"&gt;Avoid certain states as default&lt;/h2&gt;
&lt;p&gt;Using the appropriate shortcut (e.g. &lt;code&gt;T&lt;/code&gt; in &lt;code&gt;evil-org-mode&lt;/code&gt;) on a &lt;code&gt;TODO&lt;/code&gt; headline will create another &lt;code&gt;TODO&lt;/code&gt; headline below it, and it’ll default to the same &lt;code&gt;TODO&lt;/code&gt; state the current headline has.&lt;/p&gt;
&lt;p&gt;This isn’t desirable for states like &lt;code&gt;WAIT&lt;/code&gt;, as it is an unlikely starting point for a new &lt;code&gt;TODO&lt;/code&gt;. The following code shows how to control the keyword for that situation.&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;pick-default-todo-keyword-instead-of-wait&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;new-mark&lt;/span&gt; &lt;span class="nv"&gt;old-mark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;old-mark&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string=&lt;/span&gt; &lt;span class="nv"&gt;new-mark&lt;/span&gt; &lt;span class="s"&gt;"WAIT"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="s"&gt;"TODO"&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;org-todo-get-default-hook&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;pick-default-todo-keyword-instead-of-wait&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content><category term="org"></category><category term="spacemacs"></category></entry><entry><title>Solarized spacemacs</title><link href="https://forsooth.org/posts/spacemacs-solarized" rel="alternate"></link><published>2017-10-08T00:00:00+02:00</published><updated>2017-10-08T00:00:00+02:00</updated><author><name>@or</name></author><id>tag:forsooth.org,2017-10-08:/posts/spacemacs-solarized</id><summary type="html">Using the solarized themes in&amp;nbsp;spacemacs</summary><content type="html">&lt;h2 id="setup-themes"&gt;Setup themes&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://ethanschoonover.com/solarized"&gt;Solarized by Ethan Schoonover&lt;/a&gt; is wonderful, and I use it almost everywhere, just like &lt;a href="https://dejavu-fonts.github.io/"&gt;DejaVu fonts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In spacemacs I set it up like this:&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;dotspacemacs/user-init&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;setq-default&lt;/span&gt;
   &lt;span class="nv"&gt;dotspacemacs-themes&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;solarized-dark&lt;/span&gt;
                         &lt;span class="nv"&gt;solarized-light&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nv"&gt;dotspacemacs-default-font&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DejaVu Sans Mono for Powerline"&lt;/span&gt;
                               &lt;span class="ss"&gt;:size&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;
                               &lt;span class="ss"&gt;:weight&lt;/span&gt; &lt;span class="nv"&gt;normal&lt;/span&gt;
                               &lt;span class="ss"&gt;:width&lt;/span&gt; &lt;span class="nv"&gt;normal&lt;/span&gt;
                               &lt;span class="ss"&gt;:powerline-scale&lt;/span&gt; &lt;span class="mf"&gt;1.6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nv"&gt;solarized-use-variable-pitch&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
   &lt;span class="nv"&gt;solarized-scale-org-headlines&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
   &lt;span class="nv"&gt;solarized-height-minus-1&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="nv"&gt;solarized-height-plus-1&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="nv"&gt;solarized-height-plus-2&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="nv"&gt;solarized-height-plus-3&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="nv"&gt;solarized-height-plus-4&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This keeps all headings for &lt;code&gt;org-mode&lt;/code&gt; at the same font size, which guarantees that your &lt;code&gt;fill-column&lt;/code&gt; marker and tags are properly aligned across headings of different levels. It also makes navigating &lt;code&gt;org&lt;/code&gt; files more pleasant in general, as the buffer is truly monospaced again and your cursor doesn’t take any detours.&lt;/p&gt;
&lt;p&gt;I suspect there are similar heading font size settings for other themes, but I haven’t investigated that.&lt;/p&gt;
&lt;h2 id="cycle-themes"&gt;Cycle themes&lt;/h2&gt;
&lt;p&gt;With the setting above you also get the light theme, which is useful for bright days, presentations, and presentations on bright days. &lt;code&gt;SPC T n&lt;/code&gt; cycles through the two themes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: if you use &lt;a href="https://github.com/sabof/org-bullets"&gt;org-bullets&lt;/a&gt;, then you will notice that the hidden *s become visible upon switching the theme, because they still have the background color of the opposite theme. This can be remedied by saving the file and reloading it via &lt;code&gt;SPC b R&lt;/code&gt;.&lt;/p&gt;
</content><category term="org"></category><category term="spacemacs"></category><category term="solarized"></category><category term="font"></category></entry><entry><title>No indentation in org-mode</title><link href="https://forsooth.org/posts/orgmode-no-indentation" rel="alternate"></link><published>2017-10-07T00:00:00+02:00</published><updated>2017-10-07T00:00:00+02:00</updated><author><name>@or</name></author><id>tag:forsooth.org,2017-10-07:/posts/orgmode-no-indentation</id><summary type="html">Persuade org-mode not to indent after&amp;nbsp;headings</summary><content type="html">&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;
&lt;p&gt;By default org-mode indents the body after every heading based on its depth, this includes drawers and metadata like status changes.&lt;/p&gt;
&lt;div class="highlight org"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;* First heading&lt;/span&gt;
&lt;span class="cm"&gt;  CLOSED: &lt;/span&gt;&lt;span class="vc"&gt;[2017-10-07 Sat 13:22]&lt;/span&gt;
&lt;span class="cm"&gt;  :PROPERTIES:&lt;/span&gt;
&lt;span class="cm"&gt;  :CUSTOM_ID: foobar&lt;/span&gt;
&lt;span class="cm"&gt;  :END:&lt;/span&gt;
  Arbitrary text...

&lt;span class="k"&gt;** Another heading&lt;/span&gt;
   Arbitrary text...
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I started to dislike this, because for some reason it became a bit of a hassle to maintain proper indentation, especially with source/example/quote blocks, which also started at that indentation, but then it was inconsistent to drop the indentation for their content. I also struggled with finding a good indentation for bullet points: do they start with an extra space at that indentation level or not?&lt;/p&gt;
&lt;p&gt;So I found &lt;code&gt;org-indent-mode&lt;/code&gt;, which magically displays everything with indentation, without having the actual spaces in the file. That doesn’t work well for me, as it hides the actual structure of the file and things like the &lt;code&gt;fill-column&lt;/code&gt; marker and tags are all over the place.&lt;/p&gt;
&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;
&lt;p&gt;I gave up for it for a while, but recently found &lt;code&gt;org-adapt-indentation&lt;/code&gt;, which simply turns off the indentation altogether, if set to &lt;code&gt;nil&lt;/code&gt;. The only drawback is that drawers and metadata also isn’t indented. I kinda liked it for them, but I can live with that compromise.&lt;/p&gt;
&lt;div class="highlight lisp"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;org-adapt-indentation&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This makes above example look like:&lt;/p&gt;
&lt;div class="highlight org"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;* First heading&lt;/span&gt;
&lt;span class="cm"&gt;CLOSED: &lt;/span&gt;&lt;span class="vc"&gt;[2017-10-07 Sat 13:22]&lt;/span&gt;
&lt;span class="cm"&gt;:PROPERTIES:&lt;/span&gt;
&lt;span class="cm"&gt;:CUSTOM_ID: foobar&lt;/span&gt;
&lt;span class="cm"&gt;:END:&lt;/span&gt;
Arbitrary text...
&lt;span class="k"&gt;- &lt;/span&gt;bullet points
&lt;span class="k"&gt;  - &lt;/span&gt;and another

&lt;span class="k"&gt;** Another heading&lt;/span&gt;
Arbitrary text...
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So that’s great. I start bullet points at column 0, without a leading space, and all is well.&lt;/p&gt;
&lt;h2 id="migrate-existing-files"&gt;Migrate existing files&lt;/h2&gt;
&lt;p&gt;The next problem was &lt;em&gt;fixing&lt;/em&gt; my existing org files. The following script does just that:&lt;/p&gt;
&lt;div class="highlight python"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_indentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;

&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="n"&gt;indentation_to_remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;first_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;first_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="n"&gt;indentation_to_remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;first_line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;first_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="n"&gt;indentation_to_remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_indentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;indentation_to_remove&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;indentation_to_remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_indentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;indentation_to_remove&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;

    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"w"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And I ran it as seen below. This &lt;strong&gt;replaces&lt;/strong&gt; the files, so best &lt;strong&gt;back them up&lt;/strong&gt; or better yet use git, which also allows you to inspect the diff.&lt;/p&gt;
&lt;div class="highlight bash"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;find . -iname &lt;span class="s1"&gt;'*.org'&lt;/span&gt; -exec remove-org-indentation.py &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
find . -iname &lt;span class="s1"&gt;'*.org_archive'&lt;/span&gt; -exec remove-org-indentation.py &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
find templates -iname &lt;span class="s1"&gt;'*.txt'&lt;/span&gt; -exec remove-org-indentation.py &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content><category term="org"></category><category term="spacemacs"></category></entry></feed>