<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Simons blog::feed</title><subtitle>Simons blog</subtitle><link href="/"/><link href="/feed" rel="self"/><icon>/favicon.svg</icon><author><name>Simon Hayward</name></author><id>/</id><generator>App::WRT.pm / XML::Atom::SimpleFeed</generator><updated>2023-04-27T10:47:58Z</updated><entry><title>Playlist</title><link href="/2023/04/27"/><id>/2023/04/27</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Playlist&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;2023-04-27&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/_v8KCkhAf4U&#34; title=&#34;23 Skidoo   Calypso&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/w3CMb8P1Szk&#34; title=&#34;Dolly Suite, Op. 56 (Arranged for Two Guitars by Julian Bream) : I. Berceuse&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/_fbc-bvl3Yg&#34; title=&#34;Disco Ball&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/KkGx1aqIV6I&#34; title=&#34;Steve Hiett - Never Find A Girl (To Love Me Like You Do)&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/-komkjack6c&#34; title=&#34;Scribble - Mother Of Pearl&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/-cM3QrFmgqo&#34; title=&#34;Gaussian Curve - Impossible Island&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/J_nSXbAPdFA&#34; title=&#34;Niagara (ROTLA version) - Mondo 005&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/uFfToWMsT1c&#34; title=&#34;Camping in Alaska - c u in da ballpit&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/YOevVCHWV90?list=RDYOevVCHWV90&#34; title=&#34;Hiroshi Yoshimura - Something Blue.&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/JMspKiGTZ0c&#34; title=&#34;William Tyler - Man in a Hurry (Official Music Video)&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/KjQSSYOTXzk&#34; title=&#34;Khruangbin - Friday Morning (Official Video)&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
    &lt;li&gt;&lt;iframe width=&#34;640&#34; height=&#34;360&#34; src=&#34;https://www.youtube.com/embed/YEpq9RFBaew&#34; title=&#34;Storyline Fever&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/li&gt;
&lt;/ul&gt;
    
&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2023/&#34; title=&#34;2023&#34;&gt;2023&lt;/a&gt; /
&lt;a href=&#34;/2023/04/&#34; title=&#34;04&#34;&gt;04&lt;/a&gt; /
&lt;a href=&#34;/2023/04/27/&#34; title=&#34;27&#34;&gt;27&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2023-04-27T10:47:58Z</updated></entry><entry><title>Trying out Tailscale</title><link href="/2022/12/20"/><id>/2022/12/20</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Trying out Tailscale&lt;/h1&gt;


&lt;p&gt;&lt;em&gt;2022-12-20&lt;/em&gt;&lt;/p&gt;
&lt;a href=&#34;https://tailscale.com/kb/1151/what-is-tailscale/&#34;&gt;
    &lt;img src=&#34;/2022/12/tailscale.png&#34;
     width=&#34;200&#34;
     height=&#34;200&#34;
     alt=&#34;what is tailscale&#34;
     title=&#34;what is tailscale&#34; /&gt;
&lt;/a&gt;

&lt;blockquote&gt;
Tailscale is a VPN service that makes the devices and applications you own accessible anywhere in the world, securely and effortlessly. It enables encrypted point-to-point connections using the open source &lt;a href=&#34;https://www.wireguard.com/&#34;&gt;WireGuard&lt;/a&gt; protocol, which means only devices on your private network can communicate with each other.
&lt;/blockquote&gt;

&lt;p&gt;
&lt;a href=&#34;https://login.tailscale.com/admin&#34;&gt;Creating an account&lt;/a&gt; is very easy, the options to sign up are exclusively &lt;a href=&#34;https://en.wikipedia.org/wiki/Single_sign-on&#34;&gt;SSO&lt;/a&gt; as &lt;a href=&#34;https://tailscale.com/&#34;&gt;tailscale&lt;/a&gt; is not an identity provider. You can use your existing account (&lt;a href=&#34;https://tailscale.com/kb/1013/sso-providers/&#34;&gt;Google, Github, AzureAD&lt;/a&gt; etc) so utilising your identity providers existing security features (2FA/MFA) which will then apply to tailscale access.
&lt;/p&gt;

&lt;p&gt;
Each time you register a new machine/device to your private network it will appear under the &lt;strong&gt;Machines&lt;/strong&gt; tab within your account. This private network is known as a &lt;a href=&#34;https://tailscale.com/kb/1136/tailnet/&#34;&gt;tailnet&lt;/a&gt; which assigns each machine its own private ipv4 and ipv6 address, its important to note these private addresses will always stay the same for that machine/device on your network.
    &lt;a href=&#34;https://login.tailscale.com/admin&#34;&gt;&lt;img src=&#34;/2022/12/header-thumb.png&#34;
     width=&#34;816&#34;
     height=&#34;200&#34;
     alt=&#34;tailscale account header&#34;
     title=&#34;tailscale account header&#34; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Once you have created an account, you can then begin to &lt;a href=&#34;https://tailscale.com/download/&#34;&gt;install&lt;/a&gt; tailscale to add machines to your accounts &lt;a href=&#34;https://tailscale.com/kb/1136/tailnet/&#34;&gt;tailnet&lt;/a&gt; and view them on your &lt;a href=&#34;https://login.tailscale.com/admin&#34;&gt;admin console&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
I ran the install script for tailscale on a linux server, as well as installing it onto my latptop and my &lt;a href=&#34;https://tailscale.com/download/android&#34;&gt;android phone&lt;/a&gt;.
&lt;pre&gt;&lt;code&gt;
    curl -fsSL https://tailscale.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
After the install process the output is a URL which you navigate to in order to register the new machine.
&lt;/p&gt;

&lt;p&gt;
On the linux server I then enabled &lt;a href=&#34;https://tailscale.com/kb/1193/tailscale-ssh/&#34;&gt;tailscale SSH&lt;/a&gt; on the servers:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
sudo tailscale up --ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;With &lt;a href=&#34;https://tailscale.com/kb/1193/tailscale-ssh/?q=ssh#advertise-ssh-on-the-host&#34;&gt;Tailscale SSH&lt;/a&gt;, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH as normal, using Tailscale for authentication. With Tailscale SSH, Tailscale takes over port 22 for SSH connections incoming from the Tailscale network. Tailscale will authenticate and encrypt the connection over WireGuard, using Tailscale node keys. The SSH client and server will still create an encrypted SSH connection, but it will not be further authenticated.&lt;/li&gt;
&lt;li&gt;Verify high-risk connections with check mode. Optionally require certain connections, or connections as certain users (e.g., root), to re-authenticate before connecting. This allows the user to access these high-risk applications for the next 12 hours or for a specified check period before re-authenticating again.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;/p&gt;

&lt;p&gt;
I now have a remote linux server and my phone and laptop appearing under my machines on the &lt;a href=&#34;https://login.tailscale.com/admin&#34;&gt;admin console&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
By default each machine/device that is added to your network will be auto-assigned a name based on OS hostname. This can be updated so the machine/device is something more mnemonic. This also means via &lt;a href=&#34;https://tailscale.com/kb/1081/magicdns/&#34;&gt;magicdns&lt;/a&gt; you can use the name instead of the IP address.&lt;/p&gt;
&lt;a href=&#34;https://login.tailscale.com/admin&#34;&gt;&lt;img src=&#34;/2022/12/phone-name.png&#34;
     width=&#34;400&#34;
     height=&#34;305&#34;
     alt=&#34;tailscale machine dns naming&#34;
     title=&#34;tailscale machine dns naming&#34; /&gt;&lt;/a&gt;

&lt;p&gt;
On my phone after registering it, I enabled tailscale by launching the android app:
&lt;/p&gt;
&lt;img src=&#34;/2022/12/phone-enabled.png&#34;
     width=&#34;645&#34;
     height=&#34;200&#34;
     alt=&#34;tailscale enabled phone&#34;
     title=&#34;tailscale enabled phone&#34; /&gt;
&lt;p&gt;

&lt;p&gt;
To enable tailscale SSH access from my phone and laptop to those servers I updated the &lt;a href=&#34;https://tailscale.com/kb/1018/acls/?q=acl#introduction&#34;&gt;access controls&lt;/a&gt; of the tailnet policy file via the &lt;a href=&#34;https://login.tailscale.com/admin&#34;&gt;admin console&lt;/a&gt;.

&lt;blockquote&gt;
All rules eventually boil down to allowing traffic from a particular source IP address to a destination IP address and port. While you can write rules that reference IP addresses directly, it&#39;s more common to use higher-level specifiers like usernames and groups, which Tailscale automatically translates to the right low-level rules.
&lt;/blockquote&gt;
&lt;/p&gt;

&lt;p&gt;Update the SSH sections and tagOwners sections in the tailnet policy file, 
which will allow tailscale SSH access from my laptop or phone to the server using &lt;a href=&#34;https://tailscale.com/kb/1068/acl-tags/#defining-tag-owners&#34;&gt;tags&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&#34;ssh&#34;: [
    {
        &#34;action&#34;: &#34;accept&#34;,
        &#34;src&#34;:    [&#34;tag:phone&#34;, &#34;tag:laptop&#34;],
        &#34;dst&#34;:    [&#34;tag:server&#34;],
        &#34;users&#34;:  [&#34;autogroup:nonroot&#34;],
    },
],
&#34;tagOwners&#34;: {
    &#34;tag:server&#34;:     [&#34;username@github&#34;],
    &#34;tag:phone&#34;:      [&#34;username@github&#34;],
    &#34;tag:laptop&#34;:     [&#34;username@github&#34;],
},
&lt;/code&gt;&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;
For each machine/device listed under the machines tab in the admin console I then &lt;a href=&#34;https://tailscale.com/kb/1068/acl-tags/#applying-a-tag-to-a-device-in-the-admin-console&#34;&gt;assigned the ACL tags&lt;/a&gt; created via the telnet policy file to the relevant machine/device.
&lt;/p&gt;
&lt;img src=&#34;/2022/12/machines.png&#34;
     width=&#34;180&#34;
     height=&#34;274&#34;
     alt=&#34;tailscale tag machines&#34;
     title=&#34;tailscale tag machines&#34; /&gt;

&lt;p&gt;
From my laptop I can then connect over tailscale SSH:
&lt;/p&gt;
&lt;blockquote&gt;
 When you enable Tailscale SSH, Tailscale claims port 22 for the Tailscale IP address (that is, only for traffic coming from your tailnet) on the devices for which you have enabled Tailscale SSH. This routes SSH traffic for the device from the Tailscale network to an SSH server run by Tailscale, instead of your standard SSH server.
&lt;/blockquote&gt;

&lt;pre&gt;&lt;code&gt;
sudo tailscale up
ssh simon@server
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
Or via my phone using an SSH client (ie. &lt;a href=&#34;https://play.google.com/store/apps/details?id=org.connectbot&#38;hl=en_GB&#38;gl=US&#34;&gt;connectbot&lt;/a&gt;):
&lt;/p&gt;

&lt;p&gt;
You can read here how &lt;a href=&#34;https://tailscale.com/kb/1193/tailscale-ssh/#how-is-tailscale-ssh-different&#34;&gt;tailscale is different from SSH&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Other benefits to explore:
&lt;ul&gt;
    &lt;li&gt;Remove SSH access from my linux servers firewall and stop sshd running altogether&lt;/li&gt;
    &lt;li&gt;Running services on local ports and access them directly from any connected device&lt;/li&gt;
    &lt;li&gt;Share files easily between machines via &lt;a href=&#34;https://tailscale.com/kb/1106/taildrop&#34;&gt;taildrop&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;Check out using a private &lt;a href=&#34;https://github.com/tailscale/golink&#34;&gt;short link service&lt;/a&gt; for a tailnet&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2022/&#34; title=&#34;2022&#34;&gt;2022&lt;/a&gt; /
&lt;a href=&#34;/2022/12/&#34; title=&#34;12&#34;&gt;12&lt;/a&gt; /
&lt;a href=&#34;/2022/12/20/&#34; title=&#34;20&#34;&gt;20&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-12-20T17:20:40Z</updated></entry><entry><title>Approximate Pi (monte carlo method)</title><link href="/2022/11/5"/><id>/2022/11/5</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Approximate Pi (monte carlo method)&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;2022-11-05&lt;/em&gt;&lt;/p&gt;

&lt;script src=&#34;https://d3js.org/d3.v4.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;
    The last chapter of the book &lt;a href=&#34;https://www.amazon.co.uk/History-Pi-Petr-Beckmann/dp/0312381859/&#34;&gt;history of pi&lt;/a&gt; 
    which in relation to &lt;a href=&#34;https://en.wikipedia.org/wiki/Pierre-Simon_Laplace&#34;&gt;Pierre Simon Laplace&lt;/a&gt;  
    covers the &lt;a href=&#34;https://en.wikipedia.org/wiki/Monte_Carlo_method&#34;&gt;monte carlo method&lt;/a&gt; to approximate Pi.

    &lt;blockquote&gt;
        It is not difficult to calculate the probability of obtaining Pi correct to &lt;i&gt;k&lt;/i&gt; 
        decimal places in &lt;i&gt;N&lt;/i&gt; throws. The results of such a calculation show that this
        method is very inefficient as far as the numerical computation of Pi is concerned; 
        for example, the probability of obtaining Pi correct to 5 decimal places in 3,400 
        throws of the needle is less than 1.5%, which is very poor.
        Nevertheless, Laplace had discovered a powerful method of computation that did not 
        come into its own until the advent of the electronic computer. The method that Laplace 
        proposed consists in finding a numerical value by realising a random event many times 
        and observing its outcome experimentally. This is today known as a Monte Carlo method.
    &lt;/blockquote&gt;
&lt;/p&gt;

&lt;p&gt;
    Area of the circle = &#38;pi;radius&lt;sup&gt;2&lt;/sup&gt;&lt;br&gt;
    Area of the square = 4radius&lt;sup&gt;2&lt;/sup&gt;&lt;br&gt;
    The ratio of these two areas are:&lt;br&gt;
    &lt;strong&gt;Area of circle/Area of square = &#38;pi; radius&lt;sup&gt;2&lt;/sup&gt; / 4radius&lt;sup&gt;2&lt;/sup&gt; = &#38;pi; / 4&lt;/strong&gt;
    &lt;div id=&#34;area-circle&#34;&gt;&lt;/div&gt;
    &lt;script&gt;
    var margin = {top: 20, right: 20, bottom: 40, left: 60},
        width = 460 - margin.left - margin.right,
        height = 440 - margin.top - margin.bottom;
    
    var svg = d3.select(&#34;#area-circle&#34;)
      .append(&#34;svg&#34;)
        .attr(&#34;width&#34;, width + margin.left + margin.right)
        .attr(&#34;height&#34;, height + margin.top + margin.bottom)
      .append(&#34;g&#34;)
        .attr(&#34;transform&#34;,
              &#34;translate(&#34; + margin.left + &#34;,&#34; + margin.top + &#34;)&#34;);
    
    var x = d3.scaleLinear().domain([-1, 1]).range([0, width]);
    svg
      .append(&#34;g&#34;)
      .attr(&#34;transform&#34;, &#34;translate(0,&#34; + height + &#34;)&#34;)
      .call(d3.axisBottom(x));
    
    var y = d3.scaleLinear().domain([-1, 1]).range([ height, 0]);
    svg
      .append(&#34;g&#34;)
      .call(d3.axisLeft(y));
    
    svg.append(&#34;text&#34;)
        .attr(&#34;text-anchor&#34;, &#34;end&#34;)
        .attr(&#34;x&#34;, width)
        .attr(&#34;y&#34;, height + margin.top + 20)
        .text(&#34;X&#34;);
    
    svg.append(&#34;text&#34;)
        .attr(&#34;text-anchor&#34;, &#34;end&#34;)
        .attr(&#34;transform&#34;, &#34;rotate(-90)&#34;)
        .attr(&#34;y&#34;, -margin.left+20)
        .attr(&#34;x&#34;, -margin.top)
        .text(&#34;Y&#34;)
    
    svg.append(&#39;circle&#39;)
      .attr(&#39;cx&#39;, 190)
      .attr(&#39;cy&#39;, 190)
      .attr(&#39;r&#39;, 190)
      .attr(&#39;stroke&#39;, &#39;black&#39;)
      .attr(&#39;fill&#39;, &#39;#fff&#39;);
    
    svg.append(&#39;line&#39;)
    .style(&#34;stroke&#34;, &#34;red&#34;)
    .style(&#34;stroke-width&#34;, 1)
    .attr(&#34;x1&#34;, 190)
    .attr(&#34;y1&#34;, 190)
    .attr(&#34;x2&#34;, 380)
    .attr(&#34;y2&#34;, 190);

    svg.append(&#34;text&#34;)
    .attr(&#34;y&#34;, 190 - 10)
    .attr(&#34;x&#34;, 190)
    .attr(&#39;text-anchor&#39;, &#39;right&#39;)
    .text(&#34;radius=1&#34;);
    &lt;/script&gt;
&lt;/p&gt;

&lt;p&gt;
    Based on a quarter of a square (1x1) which contains a quadrant circle with a radius of 1, plot random 
    x and y points within that square and count those which lie within the quadrant circle.
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To work out if the x,y point is within the circle, the length of the hypotenuse will be less than the radius (1).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
        hypotenuse=&lt;span&gt;&#38;#8730;&lt;/span&gt; x&lt;sup&gt;2&lt;/sup&gt;+ y&lt;sup&gt;2&lt;/sup&gt; (&lt;a href=&#34;https://en.wikipedia.org/wiki/Pythagorean_theorem&#34;&gt;Pythagorean theorem&lt;/a&gt;)&lt;br&gt;
    &lt;div id=&#34;hypotenuse&#34;&gt;&lt;/div&gt;
    &lt;script&gt;
      var margin = {top: 40, right: 20, bottom: 40, left: 60},
            width = 460 - margin.left - margin.right,
            height = 460 - margin.top - margin.bottom;
        
        var svg = d3.select(&#34;#hypotenuse&#34;)
          .append(&#34;svg&#34;)
            .attr(&#34;width&#34;, width + margin.left + margin.right)
            .attr(&#34;height&#34;, height + margin.top + margin.bottom)
          .append(&#34;g&#34;)
            .attr(&#34;transform&#34;,
                  &#34;translate(&#34; + margin.left + &#34;,&#34; + margin.top + &#34;)&#34;);
        
        svg.append(&#39;circle&#39;)
          .attr(&#39;cx&#39;, 0)
          .attr(&#39;cy&#39;, 0)
          .attr(&#39;r&#39;, 380)
          .attr(&#39;stroke&#39;, &#39;black&#39;)
          .attr(&#39;fill&#39;, &#39;#fff&#39;);
          
        var x = d3.scaleLinear().domain([0, 1]).range([0, width]);
        svg
          .append(&#34;g&#34;)
          .call(d3.axisTop(x));
        
        var y = d3.scaleLinear().domain([0, 1]).range([0, height]);
        svg
          .append(&#34;g&#34;)
          .call(d3.axisLeft(y));
        
        svg.append(&#39;circle&#39;)
          .attr(&#39;cx&#39;, x(0.8))
          .attr(&#39;cy&#39;, y(0.2))
          .attr(&#39;r&#39;, 2)
          .attr(&#39;stroke&#39;, &#39;green&#39;)
          .attr(&#39;fill&#39;, &#39;green&#39;);
    
        svg.append(&#34;text&#34;)
          .attr(&#34;y&#34;, y(0.25))
          .attr(&#34;x&#34;, x(0.80))
          .attr(&#39;text-anchor&#39;, &#39;middle&#39;)
          .text(&#34;x=0.8,y=0.2&#34;);
    
        svg.append(&#39;line&#39;)
          .style(&#34;stroke&#34;, &#34;lightgreen&#34;)
          .style(&#34;stroke-width&#34;, 1)
          .attr(&#34;x1&#34;, 0)
          .attr(&#34;y1&#34;, 0)
          .attr(&#34;x2&#34;, x(0.80))
          .attr(&#34;y2&#34;, y(0.2)); 
    
        svg.append(&#39;line&#39;)
          .style(&#34;stroke&#34;, &#34;lightgreen&#34;)
          .style(&#34;stroke-width&#34;, 1)
          .attr(&#34;x1&#34;, x(0.80))
          .attr(&#34;y1&#34;, y(0.2))
          .attr(&#34;x2&#34;, x(0.80))
          .attr(&#34;y2&#34;, 0); 
    
        svg.append(&#39;line&#39;)
          .style(&#34;stroke&#34;, &#34;lightgreen&#34;)
          .style(&#34;stroke-width&#34;, 1)
          .attr(&#34;x1&#34;, x(0.80))
          .attr(&#34;y1&#34;, 0)
          .attr(&#34;x2&#34;, 0)
          .attr(&#34;y2&#34;, 0); 
    
        svg.append(&#34;text&#34;)
          .attr(&#34;x&#34;, x(0.4))
          .attr(&#34;y&#34;, y(0.15))
          .attr(&#39;text-anchor&#39;, &#39;middle&#39;)
          .text(&#34;hypotenuse&#34;);
          
        svg.append(&#34;text&#34;)
          .attr(&#34;x&#34;, x(0.4))
          .attr(&#34;y&#34;, y(0.4))
          .attr(&#39;text-anchor&#39;, &#39;middle&#39;)
          .text(&#34;hypotenuse=square root(x*x+y*y)&#34;);
        
        svg.append(&#34;text&#34;)
          .attr(&#34;x&#34;, x(0.4))
          .attr(&#34;y&#34;, y(0.5))
          .attr(&#39;text-anchor&#39;, &#39;middle&#39;)
          .text(Math.sqrt(Math.pow(0.8,2)+Math.pow(0.2,2)));
    &lt;/script&gt;
&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;&#38;pi; divided by 4 is equal to the total number of points inside the circle divided by total amount of points generated.&lt;/strong&gt;&lt;br&gt;
  &lt;strong&gt;So then the value of &#38;pi; is 4 multipled by the total number of points inside the circle divided by the total amount of points generated&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;
The higher the number of random x,y points generated the higher the level of accurate predictions as to the approximate value of pi.
&lt;/p&gt;


&lt;p&gt;
  Visualise this using &lt;a href=&#34;https://pi.simonsblog.co.uk&#34;&gt;d3 + javascript&lt;/a&gt; or click the start button: &lt;button id=&#34;start-button&#34;&gt;Start&lt;/button&gt;
  &lt;/p&gt;
  
  
  &lt;p&gt;
    &lt;div id =&#34;results&#34;&gt;&lt;/div&gt;
    &lt;div id=&#34;viz&#34;&gt;&lt;/div&gt;
    &lt;script&gt;
      var RADIUS = 190, 
        INSIDE = 0,
        BATCH = 10,
        ROW = 0;
    
      // set the dimensions and margins of the graph
      var margin = {top: 40, right: 20, bottom: 40, left: 60},
          width = 460 - margin.left - margin.right,
          height = 460 - margin.top - margin.bottom;
      
    
      function hypotenuse(x, y){
          return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
      }
    
      // create svg element, respecting margins
      var svg = d3.select(&#34;#viz&#34;)
        .append(&#34;svg&#34;)
          .attr(&#34;width&#34;, width + margin.left + margin.right)
          .attr(&#34;height&#34;, height + margin.top + margin.bottom)
        .append(&#34;g&#34;)
          .attr(&#34;transform&#34;,
                &#34;translate(&#34; + margin.left + &#34;,&#34; + margin.top + &#34;)&#34;);
      // circle
      svg.append(&#39;circle&#39;)
        .attr(&#39;cx&#39;, 0)
        .attr(&#39;cy&#39;, 0)
        .attr(&#39;r&#39;, 380)
        .attr(&#39;stroke&#39;, &#39;black&#39;)
        .attr(&#39;fill&#39;, &#39;#fff&#39;);
        
      // Add X axis
      var x = d3.scaleLinear().domain([0, 1]).range([0, width]);
      svg
        .append(&#34;g&#34;)
        .call(d3.axisTop(x));
      
      // Add Y axis
      var y = d3.scaleLinear().domain([0, 1]).range([0, height]);
      svg
        .append(&#34;g&#34;)
        .call(d3.axisLeft(y));
    
      function create_points(data){
          for (var i=0; i&lt;BATCH; i++){
              _x = Math.random();
              _y = Math.random();
              h = hypotenuse(_x, _y);
              
              // inside circle radius
              if (h &lt; 1){
                  INSIDE++;
              }
              data.push(
                  {&#34;x&#34;: _x, &#34;plot_x&#34;: x(_x), &#34;y&#34;: _y, &#34;plot_y&#34;: y(_y), &#34;h&#34;: h, &#34;inside&#34;: (h &lt; 1), &#34;#&#34;:++ROW}
              );
          }
          return data
      }
      
      function update_circle(data){
          svg.selectAll(&#34;circle&#34;)
              .data(data)
              .enter()
              .append(&#39;circle&#39;)
              .attr(&#34;cx&#34;, function(d) {return d[&#34;plot_x&#34;]})
              .attr(&#34;cy&#34;, function(d) {return d[&#34;plot_y&#34;]})
              .attr(&#34;r&#34;, 2)
              .style(&#34;fill&#34;, function(d) {return (d.inside ? &#34;rgba(60, 179, 113, .6)&#34; : &#34;rgba(255, 0, 0, .6)&#34;)});
      }
      
      // approx pi value 
      d3.select(&#39;#results&#39;).append(&#39;strong&#39;).text(&#39;Approximate Pi:&#39;);
      function update_approx_pi(data){
        d3.select(&#39;#results strong&#39;).text(&#39;Approximate Pi: &#39; + (4 * INSIDE / data.length));
      }
      
      var moving = false;
      var currentValue = 0;
      var startButton = d3.select(&#34;#start-button&#34;);
      startButton.on(&#34;click&#34;, function() {
          var button = d3.select(this);
          if (button.text() == &#34;Pause&#34;) {
              moving = false;
              clearInterval(timer);
              // timer = 0;
              button.text(&#34;Start&#34;);
          } else {
              moving = true;
              timer = setInterval(update, 100);
              button.text(&#34;Pause&#34;);
          }
      });
    
      var data = [];
      function update(){
          data = create_points(data);
          update_circle(data);
          update_approx_pi(data);
      }
    &lt;/script&gt;
  &lt;/p&gt;

&lt;p&gt;
To visualise this in &lt;a href=&#34;https://gist.github.com/simonhayward/bddec80023c0f12d0df7ef04ac6ae671&#34;&gt;python code based on 50,000 random points.&lt;/a&gt;
&lt;script src=&#34;https://gist.github.com/simonhayward/bddec80023c0f12d0df7ef04ac6ae671.js&#34;&gt;&lt;/script&gt;
&lt;/p&gt;

&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2022/&#34; title=&#34;2022&#34;&gt;2022&lt;/a&gt; /
&lt;a href=&#34;/2022/11/&#34; title=&#34;11&#34;&gt;11&lt;/a&gt; /
&lt;a href=&#34;/2022/11/5/&#34; title=&#34;5&#34;&gt;5&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-11-10T09:33:20Z</updated></entry><entry><title>Collected rules</title><link href="/2017/6/28"/><id>/2017/6/28</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Collected rules&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;2017-06-28&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Taken from the excellent book &lt;a href=&#34;https://www.amazon.co.uk/Practice-Programming-Professional-Computing/dp/020161586X&#34;&gt;The Practice of Programming&lt;/a&gt; as relevant now as it was back when it was published.&lt;/p&gt;


&lt;strong&gt;Style&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Use descriptive names for globals, short names for locals.&lt;/li&gt;
&lt;li&gt;Be consistent.&lt;/li&gt;
&lt;li&gt;Use active names for functions.&lt;/li&gt;
&lt;li&gt;Be accurate.&lt;/li&gt;
&lt;li&gt;Indent to show structure.&lt;/li&gt;
&lt;li&gt;Use the natural form for expression.&lt;/li&gt;
&lt;li&gt;Parenthesize to resolve ambiguity.&lt;/li&gt;
&lt;li&gt;Break up complex expressions.&lt;/li&gt;
&lt;li&gt;Be clear.&lt;/li&gt;
&lt;li&gt;Be careful with side effects.&lt;/li&gt;
&lt;li&gt;Use a consistent indentation and brace style.&lt;/li&gt;
&lt;li&gt;Use idioms for consistency.&lt;/li&gt;
&lt;li&gt;Use else-ifsfor multi-way decisions.&lt;/li&gt;
&lt;li&gt;Avoid function macros.&lt;/li&gt;
&lt;li&gt;Parenthesize the macro body and arguments.&lt;/li&gt;
&lt;li&gt;Give names to magic numbers.&lt;/li&gt;
&lt;li&gt;Define numbers as constants, not macros.&lt;/li&gt;
&lt;li&gt;Use character constants, not integers.&lt;/li&gt;
&lt;li&gt;Use the language to calculate the size of an object.&lt;/li&gt;
&lt;li&gt;Don&#39;t belabour the obvious.&lt;/li&gt;
&lt;li&gt;Comment functions and global data.&lt;/li&gt;
&lt;li&gt;Don&#39;t comment bad code, rewrite it.&lt;/li&gt;
&lt;li&gt;Clarify, don&#39;t confuse.&lt;/li&gt;
&lt;/ul&gt;


&lt;strong&gt;Interfaces&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Hide implementation details.&lt;/li&gt;
&lt;li&gt;Choose a small orthogonal set of primitives.&lt;/li&gt;
&lt;li&gt;Don&#39;t reach behind the user&#39;s back.&lt;/li&gt;
&lt;li&gt;Do the same thing the same way everywhere.&lt;/li&gt;
&lt;li&gt;Free a resource in the same layer that allocated it.&lt;/li&gt;
&lt;li&gt;Detect errors at a low level, handle them at a high level.&lt;/li&gt;
&lt;li&gt;Use exceptions only for exceptional situations.&lt;/li&gt;
&lt;/ul&gt;

&lt;strong&gt;Debugging&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Look for familiar patterns.&lt;/li&gt;
&lt;li&gt;Examine the most recent change.&lt;/li&gt;
&lt;li&gt;Don&#39;t make the same mistake twice.&lt;/li&gt;
&lt;li&gt;Debug it now, not later.&lt;/li&gt;
&lt;li&gt;Get a stack trace.&lt;/li&gt;
&lt;li&gt;Read before typing.&lt;/li&gt;
&lt;li&gt;Explain your code to someone else.&lt;/li&gt;
&lt;li&gt;Make the bug reproducible.&lt;/li&gt;
&lt;li&gt;Divide and conquer.&lt;/li&gt;
&lt;li&gt;Study the numerology of failures.&lt;/li&gt;
&lt;li&gt;Display output to localise your search.&lt;/li&gt;
&lt;li&gt;Write self-checking code.&lt;/li&gt;
&lt;li&gt;Write a log file.&lt;/li&gt;
&lt;li&gt;Draw a picture.&lt;/li&gt;
&lt;li&gt;Use tools.&lt;/li&gt;
&lt;li&gt;Keep records.&lt;/li&gt;
&lt;/ul&gt;

&lt;strong&gt;Testing&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Test code at its boundaries.&lt;/li&gt;
&lt;li&gt;Tes pre- and post-conditions.&lt;/li&gt;
&lt;li&gt;Use assertions.&lt;/li&gt;
&lt;li&gt;Program defensively.&lt;/li&gt;
&lt;li&gt;Check error returns.&lt;/li&gt;
&lt;li&gt;Test incrementally.&lt;/li&gt;
&lt;li&gt;Test simple parts first.&lt;/li&gt;
&lt;li&gt;Know what output to expect.&lt;/li&gt;
&lt;li&gt;Verify conservation properties.&lt;/li&gt;
&lt;li&gt;Compare independent implementations.&lt;/li&gt;
&lt;li&gt;Measure test coverage.&lt;/li&gt;
&lt;li&gt;Automate regression testing.&lt;/li&gt;
&lt;li&gt;Create self-contained tests.&lt;/li&gt;
&lt;/ul&gt;


&lt;strong&gt;Performance&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Automate timing measurements.&lt;/li&gt;
&lt;li&gt;Use a profiler.&lt;/li&gt;
&lt;li&gt;Concentrate on the hot spots.&lt;/li&gt;
&lt;li&gt;Draw a picture.&lt;/li&gt;
&lt;li&gt;Use a better algorithm or data structure.&lt;/li&gt;
&lt;li&gt;Enable compiler optimizations.&lt;/li&gt;
&lt;li&gt;Tune the code.&lt;/li&gt;
&lt;li&gt;Don&#39;t optimise what doesn&#39;t matter.&lt;/li&gt;
&lt;li&gt;Collect common subexpressions.&lt;/li&gt;
&lt;li&gt;Replace expensive operations by cheap ones.&lt;/li&gt;
&lt;li&gt;Unroll or eliminate loops.&lt;/li&gt;
&lt;li&gt;Cache frequently-used values.&lt;/li&gt;
&lt;li&gt;Write a special-purpose allocator.&lt;/li&gt;
&lt;li&gt;Buffer input and output.&lt;/li&gt;
&lt;li&gt;Handle special cases separately.&lt;/li&gt;
&lt;li&gt;Precompute results.&lt;/li&gt;
&lt;li&gt;Use approximate values.&lt;/li&gt;
&lt;li&gt;Rewrite in a lower-level language.&lt;/li&gt;
&lt;li&gt;Save space by using the smallest possible data type.&lt;/li&gt;
&lt;li&gt;Don&#39;t store what you can easily recompute.&lt;/li&gt;
&lt;/ul&gt;


&lt;strong&gt;Portability&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Stick to the standard.&lt;/li&gt;
&lt;li&gt;Program in the mainstream.&lt;/li&gt;
&lt;li&gt;Beware of language trouble spots.&lt;/li&gt;
&lt;li&gt;Try several compilers.&lt;/li&gt;
&lt;li&gt;Use standard libraries.&lt;/li&gt;
&lt;li&gt;Use only features available everywhere.&lt;/li&gt;
&lt;li&gt;Avoid conditional compilation.&lt;/li&gt;
&lt;li&gt;Localise system dependencies in separate files.&lt;/li&gt;
&lt;li&gt;Hide system dependencies behind interfaces.&lt;/li&gt;
&lt;li&gt;Use text for data exchange.&lt;/li&gt;
&lt;li&gt;Use a fixed byte order for data exchange.&lt;/li&gt;
&lt;li&gt;Change the name if you change the specification.&lt;/li&gt;
&lt;li&gt;Maintain compatibility with existing programs and data.&lt;/li&gt;
&lt;li&gt;Don&#39;t assume ASCII.&lt;/li&gt;
&lt;li&gt;Don&#39;t assume English.&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2017/&#34; title=&#34;2017&#34;&gt;2017&lt;/a&gt; /
&lt;a href=&#34;/2017/6/&#34; title=&#34;6&#34;&gt;6&lt;/a&gt; /
&lt;a href=&#34;/2017/6/28/&#34; title=&#34;28&#34;&gt;28&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-11-08T12:46:17Z</updated></entry><entry><title>Sockets and cwrap</title><link href="/2014/5/1"/><id>/2014/5/1</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Sockets and cwrap&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;2014-05-01&lt;/em&gt;&lt;/p&gt;


&lt;p&gt;Have you ever wanted to run a software stack locally, testing client/server
interactions, all on the same machine, under a normal user account?&lt;/p&gt;

&lt;p&gt;Maybe &lt;a href=&#34;http://cwrap.org&#34;&gt;cwrap&lt;/a&gt; could help.&lt;/p&gt;

&lt;p&gt;What is &lt;a href=&#34;http://cwrap.org&#34;&gt;cwrap&lt;/a&gt;?&lt;/p&gt;

&lt;blockquote&gt;
    cwrap is a set of tools to create a fully isolated network environment to
    test client/server components on a single host.
    It provides synthetic account information, hostname resolution and
    support for privilege separation. The heart of cwrap consists of three
    libraries you can preload to any executable.
&lt;/blockquote&gt;

&lt;a href=&#34;http://cwrap.org&#34;&gt;cwrap&lt;/a&gt; consists of three libraries:

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://git.samba.org/?p=socket_wrapper.git&#34;&gt;socket_wrapper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://git.samba.org/?p=nss_wrapper.git&#34;&gt;nss_wrapper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://git.samba.org/?p=uid_wrapper.git&#34;&gt;uid_wrapper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
These libraries allow you to preload to a binary and so replacing library function calls,
by using **LD_PRELOAD**.
&lt;/p&gt;


&lt;p&gt;From the `ld.so`_ man pages:&lt;/p&gt;

&lt;blockquote&gt;
    LD_PRELOAD
              A list of additional, user-specified, ELF shared libraries to
              be loaded before all others.  The items of the list can be
              separated by spaces or colons.  This can be used to
              selectively override functions in other shared libraries.
&lt;/blockquote&gt;

&lt;p&gt;
I&#39;m going to look at &lt;a href=&#34;http://git.samba.org/?p=socket_wrapper.git&#34;&gt;socket_wrapper&lt;/a&gt; and some examples of how to redirect tcp sockets to use unix sockets.
&lt;/p&gt;


&lt;strong&gt;Installation&lt;/strong&gt;

&lt;i&gt;I&#39;m installing socket_wrapper-1.0.1 on Ubuntu 13.04.&lt;/i&gt;

&lt;p&gt;
The author of this software is &lt;a href=&#34;http://blog.cryptomilk.org&#34;&gt;Andreas Schneider&lt;/a&gt;, so before installing this I&#39;m going to import his &lt;a href=&#34;http://blog.cryptomilk.org/2013/10/07/new-pgp-key/&#34;&gt;pgp key&lt;/a&gt;.
&lt;/p&gt;


&lt;strong&gt;PGP keys&lt;/strong&gt;

&lt;pre&gt;&lt;code&gt;
    simon@X220:~$ wget --quiet http://www.cryptomilk.org/0xCC014E3D-asn@cryptomilk.org-gpg_key.asc
    simon@X220:~$ gpg --import 0xCC014E3D-asn@cryptomilk.org-gpg_key.asc
    gpg: key CC014E3D: public key &#34;Andreas Schneider &lt;asn@cryptomilk.org&gt;&#34; imported
    gpg: Total number processed: 1
    gpg:               imported: 1  (RSA: 1)
    gpg: no ultimately trusted keys found

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
The project is part of the samba suite of software, so it&#39;s available for download
via the &lt;a href=&#34;https://ftp.samba.org/pub/cwrap/&#34;&gt;samba&lt;/a&gt; site.
&lt;/p&gt;

&lt;strong&gt;Download&lt;/strong&gt;

&lt;p&gt;
The latest version of &lt;a href=&#34;http://git.samba.org/?p=socket_wrapper.git&#34;&gt;socket_wrapper&lt;/a&gt; is &lt;a href=&#34;https://ftp.samba.org/pub/cwrap/socket_wrapper-1.0.1.tar.gz&#34;&gt;socket_wrapper-1.0.1.tar.gz&lt;/a&gt; (04-Feb-2014 09:04, 36K)

&lt;pre&gt;&lt;code&gt;

    simon@X220:~$ mkdir sockets
    simon@X220:~$ cd sockets
    simon@X220:~/sockets$ wget --quiet https://ftp.samba.org/pub/cwrap/socket_wrapper-1.0.1.tar.gz
    simon@X220:~/sockets$ wget --quiet https://ftp.samba.org/pub/cwrap/socket_wrapper-1.0.1.tar.asc
    simon@X220:~/sockets$ gzip -d socket_wrapper-1.0.1.tar.gz
    simon@X220:~/sockets$ gpg --verify socket_wrapper-1.0.1.tar.asc
    gpg: Signature made Tue 04 Feb 2014 16:04:36 GMT using RSA key ID CC014E3D
    gpg: Good signature from &#34;Andreas Schneider &lt;asn@cryptomilk.org&gt;&#34;
    gpg:                 aka &#34;Andreas Schneider &lt;asn@samba.org&gt;&#34;
    gpg: WARNING: This key is not certified with a trusted signature!
    gpg:          There is no indication that the signature belongs to the owner.
    Primary key fingerprint: 8DFF 53E1 8F2A BC8D 8F3C  9223 7EE0 FC4D CC01 4E3D
    simon@X220:~/sockets$ tar -xf socket_wrapper-1.0.1.tar
    simon@X220:~/sockets$ cd socket_wrapper-1.0.1/
    simon@X220:~/sockets/socket_wrapper-1.0.1$ mkdir builddir
    simon@X220:~/sockets/socket_wrapper-1.0.1$ cd builddir/

&lt;/code&gt;&lt;/pre&gt;


&lt;strong&gt;Requirements&lt;/strong&gt;


&lt;a href=&#34;http://www.cmake.org/&#34;&gt;cmake&lt;/a&gt; is a requirement to build.

&lt;pre&gt;&lt;code&gt;
    simon@X220:~/sockets/socket_wrapper-1.0.1/builddir$ sudo aptitude install cmake
&lt;/code&gt;&lt;/pre&gt;


&lt;strong&gt;Compile and Install&lt;/strong&gt;


&lt;pre&gt;&lt;code&gt;
    simon@X220:~/sockets/socket_wrapper-1.0.1/builddir$ cmake .. -DCMAKE_INSTALL_PREFIX:PATH=~/sockets/bin
    -- The C compiler identification is GNU 4.7.3
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    ......
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/simon/sockets/socket_wrapper-1.0.1/builddir
    simon@X220:~/sockets/socket_wrapper-1.0.1/builddir$ make &#38;&#38; make install
    Scanning dependencies of target socket_wrapper
    [100%] Building C object src/CMakeFiles/socket_wrapper.dir/socket_wrapper.c.o
    Linking C shared library libsocket_wrapper.so
    [100%] Built target socket_wrapper
    [100%] Built target socket_wrapper
    Install the project...
    -- Install configuration: &#34;&#34;
    -- Installing: /home/simon/sockets/bin/lib/pkgconfig/socket_wrapper.pc
    -- Installing: /home/simon/sockets/bin/lib/cmake/socket_wrapper-config-version.cmake
    -- Installing: /home/simon/sockets/bin/lib/cmake/socket_wrapper-config.cmake
    -- Installing: /home/simon/sockets/bin/lib/libsocket_wrapper.so.0.0.1
    -- Installing: /home/simon/sockets/bin/lib/libsocket_wrapper.so.0
    -- Installing: /home/simon/sockets/bin/lib/libsocket_wrapper.so
&lt;/code&gt;&lt;/pre&gt;


&lt;strong&gt;Running netcat&lt;/strong&gt;

&lt;p&gt;
In one terminal run netcat binding to IP: 127.0.0.10 on port 7
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
    simon@X220:~/sockets/socket_wrapper-1.0.1/builddir$ cd ~/sockets/bin/
    simon@X220:~/sockets/bin$ mktemp -d
    /tmp/tmp.hxyAQf3Pda
    simon@X220:~/sockets/bin$ LD_PRELOAD=lib/libsocket_wrapper.so \
    &gt; SOCKET_WRAPPER_DIR=/tmp/tmp.hxyAQf3Pda \
    &gt; SOCKET_WRAPPER_DEFAULT_IFACE=10 nc -v -l 127.0.0.10 7
    Listening on [127.0.0.10] (family 0, port 7)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
In a seperate terminal send a message to that IP and port.
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
    simon@X220:~/sockets/bin$ LD_PRELOAD=lib/libsocket_wrapper.so \
    &gt; SOCKET_WRAPPER_DIR=/tmp/tmp.hxyAQf3Pda \
    &gt; SOCKET_WRAPPER_DEFAULT_IFACE=10 nc -v 127.0.0.10 7
    Connection to 127.0.0.10 7 port [tcp/echo] succeeded!
    Hello!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&#39;Hello!&#39; is then received by the listening netcat&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;

    simon@X220:~/sockets/bin$ LD_PRELOAD=lib/libsocket_wrapper.so \
    &gt; SOCKET_WRAPPER_DIR=/tmp/tmp.hxyAQf3Pda \
    &gt; SOCKET_WRAPPER_DEFAULT_IFACE=10 nc -v -l 127.0.0.10 7
    Listening on [127.0.0.10] (family 0, port 7)
    Connection from [127.0.0.10] port 7 [tcp/echo] accepted (family 2, sport 41505)
    Hello!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
Instead of netcat using tcp sockets, SOCKET_WRAPPER_DIR contains the unix sockets created in place of those tcp sockets.
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
    simon@X220:~/sockets/bin$ file /tmp/tmp.hxyAQf3Pda/* &#38;&#38; lsof /tmp/tmp.hxyAQf3Pda/*
    /tmp/tmp.hxyAQf3Pda/T0A0007: socket
    /tmp/tmp.hxyAQf3Pda/T0AA221: socket
    COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF    NODE NAME
    nc      31334 simon    5u  unix 0x0000000000000000      0t0 2265223 /tmp/tmp.hxyAQf3Pda/T0A0007
    nc      31505 simon    3u  unix 0x0000000000000000      0t0 2267187 /tmp/tmp.hxyAQf3Pda/T0AA221
&lt;/code&gt;&lt;/pre&gt;


&lt;strong&gt;Running Nginx&lt;/strong&gt;

&lt;p&gt;
I created the most basic of nginx confs as a simple example:
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
    simon@X220:~$ mkdir -p nginx-local/www
    simon@X220:~$ touch nginx-local/www/test
    simon@X220:~$ cd nginx-local
    simon@X220:~/nginx-local$ vi nginx.conf
    error_log /home/simon/nginx-local/error.log;
    worker_processes 1;
    events {
        worker_connections 3;
    }
    http {
        server {
            listen 127.0.0.10:7;
            root /home/simon/nginx-local/www;
            location / {
                autoindex on;
                access_log off;
            }
        }
    }

    simon@X220:~/nginx-local$ LD_PRELOAD=/home/simon/sockets/bin/lib/libsocket_wrapper.so \
    &gt; SOCKET_WRAPPER_DIR=/tmp/tmp.hxyAQf3Pda \
    &gt; SOCKET_WRAPPER_DEFAULT_IFACE=10 \
    &gt; /usr/sbin/nginx -c /home/simon/nginx-local/nginx.conf \
    &gt; -g &#34;pid /home/simon/nginx-local/nginx.pid;&#34;


    Note: You may receive an [alert] warning from nginx, that is cannot read the default error_log.
    As of version 0.7.53, nginx will use the compiled-in default error log before, reading in
    the config file.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, check that Nginx is running&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;

    simon@X220:~/nginx-local$ netstat -nlp | grep $(cat ~/nginx-local/nginx.pid)
    (Not all processes could be identified, non-owned process info
     will not be shown, you would have to be root to see it all.)
    unix  2      [ ACC ]     STREAM     LISTENING     2266669  919/nginx.pid;      /tmp/tmp.hxyAQf3Pda/T0A0007
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
Connect as a client to the server and capture conversation (SOCKET_WRAPPER_PCAP_FILE)
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
    simon@X220:~/nginx-local$ LD_PRELOAD=/home/simon/sockets/bin/lib/libsocket_wrapper.so \
    &gt; SOCKET_WRAPPER_DIR=/tmp/tmp.hxyAQf3Pda \
    &gt; SOCKET_WRAPPER_PCAP_FILE=/tmp/nginx.pcap \
    &gt; SOCKET_WRAPPER_DEFAULT_IFACE=10 telnet 127.0.0.10 7
    Trying 127.0.0.10...
    Connected to 127.0.0.10.
    Escape character is &#39;^]&#39;.
    GET / HTTP/1.1
    Host: 127.0.0.10

    HTTP/1.1 200 OK
    Server: nginx/1.2.6 (Ubuntu)
    Date: Thu, 01 May 2014 15:26:31 GMT
    Content-Type: text/html
    Transfer-Encoding: chunked
    Connection: keep-alive

    104
    &#38;lt;html&#38;gt;
    &#38;lt;head&#38;gt;&#38;lt;title&#38;gt;Index of /&#38;lt;/title&#38;gt;&#38;lt;/head&#38;gt;
    &#38;lt;body bgcolor=&#38;quot;white&#38;quot;&#38;gt;
    &#38;lt;h1&#38;gt;Index of /&#38;lt;/h1&#38;gt;&#38;lt;hr&#38;gt;&#38;lt;pre&#38;gt;&#38;lt;a href=&#38;quot;../&#38;quot;&#38;gt;../&#38;lt;/a&#38;gt;
    &#38;lt;a href=&#38;quot;test&#38;quot;&#38;gt;test&#38;lt;/a&#38;gt;                                               01-May-2014 14:10                   0
    &#38;lt;/pre&#38;gt;&#38;lt;hr&#38;gt;&#38;lt;/body&#38;gt;
    &#38;lt;/html&#38;gt;
    0

    simon@X220:~/nginx-local$ kill -QUIT $(cat /home/simon/nginx-local/nginx.pid)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
All of this network conversation is caught in the pcap file and so can be loaded into
wireshark.
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
    simon@X220:~/nginx-local$ wireshark /tmp/nginx.pcap
&lt;/code&gt;&lt;/pre&gt;


&lt;strong&gt;Conclusion&lt;/strong&gt;


&lt;p&gt;This throws up a whole host of possibilities to test client/server interactions
that are required for your application and all tested locally as a normal
(non root) user.
&lt;/p&gt;

&lt;p&gt;
The ability to easily translate IPv4 and IPv6 addresses to a unix sockets,
and simulate binding to privileged ports (&lt; 1024), allows for
easier local testing, if your application requires a lot of network interactions
as part of it&#39;s test suite.
&lt;/p&gt;

&lt;p&gt;
You may also be interested in the other components of &lt;a href=&#34;http://cwrap.org&#34;&gt;cwrap&lt;/a&gt;
&lt;/p&gt;

&lt;a href=&#34;http://git.samba.org/?p=nss_wrapper.git&#34;&gt;nss_wrapper&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Provides information for user and group accounts&lt;/li&gt;
&lt;li&gt;Network name resolution using a hosts file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Name resolution could work well with &lt;a href=&#34;http://git.samba.org/?p=socket_wrapper.git&#34;&gt;socket_wrapper&lt;/a&gt; and works much the same way.
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
    simon@X220:~/nss_wrapper$ echo &#34;127.0.0.10  simonsblog.co.uk&#34; &gt; hosts
    simon@X220:~/nss_wrapper$ LD_PRELOAD=&#34;bin/lib/libnss_wrapper.so&#34; \
    &gt; NSS_WRAPPER_HOSTS=hosts \
    &gt; python -c &#34;import socket; print(socket.gethostbyname(&#39;simonsblog.co.uk&#39;))&#34;
    127.0.0.10
&lt;/code&gt;&lt;/pre&gt;

&lt;a href=&#34;http://git.samba.org/?p=uid_wrapper.git&#34;&gt;uid_wrapper&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Allows uid switching as a normal user.&lt;/li&gt;
&lt;li&gt;Start any application making it believe it is running as root.&lt;/li&gt;
&lt;li&gt;Support for user/group changing in the local thread using the syscalls (like glibc).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Check out the article on &lt;a href=&#34;https://lwn.net/Articles/595320/&#34;&gt;lwn.net&lt;/a&gt; and &lt;a href=&#34;http://cwrap.org&#34;&gt;cwrap&lt;/a&gt; for more info.
&lt;/p&gt;


&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2014/&#34; title=&#34;2014&#34;&gt;2014&lt;/a&gt; /
&lt;a href=&#34;/2014/5/&#34; title=&#34;5&#34;&gt;5&lt;/a&gt; /
&lt;a href=&#34;/2014/5/1/&#34; title=&#34;1&#34;&gt;1&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-11-08T12:45:57Z</updated></entry><entry><title>Switching from Gmail to Fastmail</title><link href="/2013/12/6"/><id>/2013/12/6</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Switching from Gmail to Fastmail&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;2013-12-06&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;
&lt;a href=&#34;/2013/12/header.png&#34;&gt;&lt;img src=&#34;/2013/12/header-thumb.png&#34;
     width=&#34;400&#34;
     height=&#34;143&#34;
     alt=&#34;fastmail&#34;
     title=&#34;fastmail&#34; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Three months ago I decided to try out &lt;a href=&#34;http://www.fastmail.to/?STKI=11487141&#34;&gt;fastmail.fm&lt;/a&gt; after having used
google&#39;s &lt;a href=&#34;https://gmail.google.com&#34;&gt;gmail&lt;/a&gt; as my primary email for a number of years. I kept seeing
a number of people moving away from google after the &lt;a href=&#34;http://www.theguardian.com/world/the-nsa-files&#34;&gt;NSA revelations&lt;/a&gt;  and
the admission that &lt;a href=&#34;http://www.theguardian.com/technology/2013/aug/14/google-gmail-users-privacy-email-lawsuit&#34;&gt;gmail users cannot expect privacy&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
I have no complaints about using &lt;a href=&#34;https://gmail.google.com&#34;&gt;gmail&lt;/a&gt; all these years, for a free service
it is better than most other free options and their service has never been
down or caused me any issues.
&lt;/p&gt;

&lt;p&gt;
However you do end up living in this &lt;i&gt;google product world&lt;/i&gt;, an all
encompassing world in which they will end up knowing more about you than
even your family will know about you.
&lt;/p&gt;

&lt;p&gt;
If something is free is it really right
to expect privacy? Which goes along with the saying:
&lt;/p&gt;

&lt;blockquote&gt;
    &#34;If you don&#39;t pay for the product, then you are the product&#34;.
&lt;/blockquote&gt;

&lt;p&gt;
Maybe this is true, in which case you need to look at other options,
&lt;a href=&#34;http://www.fastmail.to/?STKI=11487141&#34;&gt;fastmail.fm&lt;/a&gt; was one of those options.
Their offer of &lt;i&gt;Providing a Reliable and Clutter-Free Email Experience&lt;/i&gt; who
take privacy seriously, was attractive. While they also suggest that being an
Australian company, they &lt;a href=&#34;http://www.theguardian.com/technology/2013/oct/07/australias-fastmail-secure-email-nsa&#34;&gt;fall outside the (US) NSA&#39;s jurisdiction&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
So I initially signed up for a free trial account on the Enhanced ($40 a year)
account, which includes:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;15 GB email storage&lt;/li&gt;
&lt;li&gt;5 GB file storage&lt;/li&gt;
&lt;li&gt;Use your own domain&lt;/li&gt;
&lt;li&gt;No included SMS&lt;/li&gt;
&lt;li&gt;Advanced anti-spam&lt;/li&gt;
&lt;li&gt;No ads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
You can choose an email address from a substantial (~115)
list of &lt;i&gt;fastmail&lt;/i&gt; like top level domains, a selection being:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; fastmail.fm&lt;/li&gt;
&lt;li&gt; fastmail.to&lt;/li&gt;
&lt;li&gt; fastmail.us&lt;/li&gt;
&lt;li&gt; fastmail.cn&lt;/li&gt;
&lt;li&gt; fastmail.com.au&lt;/li&gt;
&lt;li&gt; fastmail.jp&lt;/li&gt;
&lt;li&gt; fastmail.net&lt;/li&gt;
&lt;li&gt; fastmail.es&lt;/li&gt;
&lt;li&gt; fastmail.co.uk&lt;/li&gt;
&lt;li&gt; fastmail.in&lt;/li&gt;
&lt;li&gt; fastmail.im&lt;/li&gt;
&lt;li&gt; fastmail.nl&lt;/li&gt;
&lt;li&gt; fastmail.se&lt;/li&gt;
&lt;li&gt; fastmail.mx&lt;/li&gt;
&lt;li&gt; fastmail.tw&lt;/li&gt;
&lt;li&gt; fmail.co.uk&lt;/li&gt;
&lt;li&gt; sent.com&lt;/li&gt;
&lt;li&gt; myfastmail.com&lt;/li&gt;
&lt;li&gt; speedymail.org&lt;/li&gt;
&lt;li&gt; fast-email.com&lt;/li&gt;
&lt;li&gt; fastimap.com&lt;/li&gt;
&lt;li&gt; fast-mail.org&lt;/li&gt;
&lt;li&gt; fastemail.us&lt;/li&gt;
&lt;li&gt; operamail.com&lt;/li&gt;

&lt;/ul&gt;

After which I set up my fastmail account to use my own domain name, simonsblog.co.uk.
So I switched my DNS MX records via my &lt;a href=&#34;https://dnsimple.com/r/3d06c548b79445&#34;&gt;dnsimple&lt;/a&gt; DNS hosting provider
to point to fastmails servers. Fastmail do offer to handle DNS
for you, but I&#39;m already happily using the excellent service provided by
&lt;a href=&#34;https://dnsimple.com/r/3d06c548b79445&#34;&gt;dnsimple&lt;/a&gt;  for all my DNS hosting.

&lt;pre&gt;&lt;code&gt;
    simon@X220:~$ dig +short simonsblog.co.uk mx
    20 in2-smtp.messagingengine.com.
    10 in1-smtp.messagingengine.com.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
Added an SPF record.
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
    simon@X220:~$ dig simonsblog.co.uk +short spf
    &#34;v=spf1 include:spf.messagingengine.com -all&#34;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
I then added a TXT record for my DKIM key, retrieved via Fastmail.fm -&gt;
Advanced settings -&gt; Virtual Domains
&lt;/p&gt;

&lt;p&gt;
I also set up an alias (CNAME) to access webmail via my domain.
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
    simon@X220:~$ dig +short mail.simonsblog.co.uk cname
    www.fastmail.fm.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
While under this free trial, &lt;a href=&#34;http://www.fastmail.to/?STKI=11487141&#34;&gt;fastmail.fm&lt;/a&gt; announced that &lt;a href=&#34;http://blog.fastmail.fm/2013/09/25/exciting-news-fastmail-staff-purchase-the-business-from-opera/&#34;&gt;staff had purchased the
business back from opera&lt;/a&gt; which was getting noticed on &lt;a href=&#34;https://twitter.com/jacobian/status/383084245784076288&#34;&gt;twitter&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
This is a key issue for me, for staff to un-acquire itself just shows the belief
the team have in it.
&lt;/p&gt;

&lt;p&gt;
So three months in and I&#39;m happily switched to using &lt;a href=&#34;http://www.fastmail.to/?STKI=11487141&#34;&gt;fastmail.fm&lt;/a&gt; as my primary
email address. Some nice features are:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Fast loading&lt;/li&gt;
&lt;li&gt; Infinite scrolling&lt;/li&gt;
&lt;li&gt; Extensive configuration&lt;/li&gt;
&lt;li&gt; Ad free&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Some not nice features:
&lt;/p&gt;

&lt;p&gt;No native mobile app (I&#39;m using &lt;a href=&#34;https://play.google.com/store/apps/details?id=com.maildroid.pro&#38;hl=en&#34;&gt;MailDroid Pro&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;
I haven&#39;t totally unplugged myself from gmail, I still forward all gmail to
my fastmail account, but these are becoming less and less as I move more
accounts over to use my new address.
&lt;/p&gt;

&lt;p&gt;
The process to switch has been relatively pain free and for $40
a year seems a small price to pay to have secure and private email.
&lt;/p&gt;

&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2013/&#34; title=&#34;2013&#34;&gt;2013&lt;/a&gt; /
&lt;a href=&#34;/2013/12/&#34; title=&#34;12&#34;&gt;12&lt;/a&gt; /
&lt;a href=&#34;/2013/12/6/&#34; title=&#34;6&#34;&gt;6&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-11-03T21:03:23Z</updated></entry><entry><title>Tiling window manager: i3</title><link href="/2012/11/9"/><id>/2012/11/9</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Tiling window manager: i3&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;2012-11-09&lt;/em&gt;&lt;/p&gt;


&lt;p&gt;After using the &lt;a href=&#34;http://awesome.naquadah.org/&#34;&gt;awesome&lt;/a&gt; window manager for the last few years, I&#39;ve
switched over to a new tiling window manger &lt;a href=&#34;http://i3wm.org&#34;&gt;i3&lt;/a&gt; - after trying it out,
I&#39;ve now completely switched over and really like the ease of use and
increased functionality it provides.
&lt;/p&gt;


&lt;a href=&#34;http://en.wikipedia.org/wiki/Tiling_window_manager&#34;&gt;Tiling window managers&lt;/a&gt; allow me to manage my screen space much more
efficiently and mean I can work within multiple windows easily. I like
the simplicity of &lt;a href=&#34;http://i3wm.org&#34;&gt;i3&lt;/a&gt;, it allows for &lt;a href=&#34;http://i3wm.org/docs/userguide.html#_changing_the_container_layout&#34;&gt;3 container layouts&lt;/a&gt;
splith/splitv, stacking, tabbed. I also find it &lt;i&gt;very&lt;/i&gt; easy to modify
your keyboard mappings via a simple (plain text rather than a &lt;a href=&#34;http://www.lua.org/&#34;&gt;lua&lt;/a&gt;
config file in the case of awesome wm) file in your home directory.
&lt;a href=&#34;https://gist.github.com/simonhayward/11316105&#34;&gt;~/.i3/config&lt;/a&gt;.This config file is created for you based on default
settings when you first use i3.


&lt;p&gt;
&lt;a href=&#34;/2012/11/i3-screen.png&#34;&gt;&lt;img src=&#34;/2012/11/i3-screen-thumb.png&#34;
     width=&#34;700&#34;
     height=&#34;394&#34;
     alt=&#34;i3&#34;
     title=&#34;i3&#34; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
I didn&#39;t need to add much to mine, just some short cuts I would need,
suspend/lock (I&#39;m using &lt;a href=&#34;http://i3wm.org/i3lock/&#34;&gt;i3lock&lt;/a&gt; - which comes with the i3 suite) - the
defaults are sane and get&#39;s you up and running quickly.

&lt;a href=&#34;http://i3wm.org&#34;&gt;i3&lt;/a&gt; has good support for multi monitors and uses &lt;a href=&#34;http://xorg.freedesktop.org/wiki/Projects/XRandR&#34;&gt;xrandr&lt;/a&gt; by default.
&lt;/p&gt;

&lt;p&gt;
What is most impressive is not only the simplicity of the configuration
but the speed of it, and the minimal memory space it occupies. The
&lt;a href=&#34;http://i3wm.org/docs/&#34;&gt;docs&lt;/a&gt; are extremely well laid out and answer almost all questions you
may have. There is a good &lt;a href=&#34;http://www.youtube.com/watch?v=QnYN2CTb1hM&#34;&gt;google tech talk video on i3&lt;/a&gt; from &lt;a href=&#34;http://michael.stapelberg.de/&#34;&gt;Michael
Stapelberg&lt;/a&gt; outlining the design decisions they took and why they
decided to built yet another window tiling manager.
&lt;p&gt;

&lt;p&gt;
My main reasons for switching are:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed&lt;/li&gt;
&lt;li&gt;Simplicity&lt;/li&gt;
&lt;li&gt;Complete test suite&lt;/li&gt;
&lt;li&gt;Clean design&lt;/li&gt;
&lt;li&gt;Great documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
If you are using or considering switching to a tiling manager, I
recommend trying &lt;a href=&#34;http://i3wm.org&#34;&gt;i3&lt;/a&gt;, if you are using ubuntu or debian it&#39;s even
easier to install as you can use their &lt;a href=&#34;http://i3wm.org/docs/repositories.html&#34;&gt;repositories&lt;/a&gt;.
&lt;/p&gt;

&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2012/&#34; title=&#34;2012&#34;&gt;2012&lt;/a&gt; /
&lt;a href=&#34;/2012/11/&#34; title=&#34;11&#34;&gt;11&lt;/a&gt; /
&lt;a href=&#34;/2012/11/9/&#34; title=&#34;9&#34;&gt;9&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-11-03T20:39:56Z</updated></entry><entry><title>Rotate arbitrary</title><link href="/2012/7/21"/><id>/2012/7/21</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Rotate arbitrary&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;2012-07-21&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another way to rotate by arbitrary values.&lt;/p&gt;

&lt;p&gt;
You can in python 2.x - just str.encode(&#34;rot13&#34;) - but for other
rotations you could use the following (for ascii):
&lt;/p&gt;

&lt;script src=&#34;https://gist.github.com/simonhayward/3156361.js&#34;&gt;&lt;/script&gt;

&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2012/&#34; title=&#34;2012&#34;&gt;2012&lt;/a&gt; /
&lt;a href=&#34;/2012/7/&#34; title=&#34;7&#34;&gt;7&lt;/a&gt; /
&lt;a href=&#34;/2012/7/21/&#34; title=&#34;21&#34;&gt;21&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-11-03T21:10:16Z</updated></entry><entry><title>Favourite quotes</title><link href="/2012/6/25"/><id>/2012/6/25</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Favourite quotes&lt;/h1&gt;


&lt;p&gt;&lt;em&gt;2012-06-25&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;
A selection of my favourite quotes I&#39;ve come across recently
&lt;/p&gt;


&lt;blockquote&gt;
&lt;ul&gt;
   &lt;li&gt;L1 cache - 3s grabbing a piece of paper&lt;/li&gt;
   &lt;li&gt;L2 cache - 14s picking a book from a shelf&lt;/li&gt;
   &lt;li&gt;System RAM - 4m walk down the hall&lt;/li&gt;
   &lt;li&gt;Hard drive seek - Like leaving the building to roam the earth for one year and three months&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Gustavo Duarte (via Brandon Rhodes at pycon us - &lt;a href=&#34;http://pyvideo.org/video/717/python-linkers-and-virtual-memory&#34;&gt;Python Linkers and
Virtual Memory&lt;/a&gt;)
&lt;/p&gt;

&lt;blockquote&gt;
The purpose of software engineering is to control complexity, not to create it.
&lt;/blockquote&gt;

&lt;p&gt;
Pamela Zave (via Jon Bentley&#39;s - &lt;a href=&#34;http://www.amazon.co.uk/Programming-Pearls-ACM-Press-Bentley/dp/0201657880&#34;&gt;Programming Pearls&lt;/a&gt;)
&lt;/p&gt;

&lt;blockquote&gt;
I think it&#39;s better to give users the rope they want than to try and
   prevent them from hanging themselves, since otherwise they&#39;ll just
   use the power cords as ropes and electrocute themselves.
&lt;/blockquote&gt;

&lt;p&gt;
Guido van Rossum - &lt;a href=&#34;https://lwn.net/Articles/500485/&#34;&gt;resolving a TZ-aware local time request&lt;/a&gt;
&lt;/p&gt;

&lt;blockquote&gt;
I think that if I was running a company like Microsoft I would ask
   everyone to read Code Complete, but if I were running a start up, I
   would ask no-one to read Code Complete. Code Complete is all about
   being exceptionally conservative with your programming practise. If
   you have a small company full of brilliant programmers you don&#39;t
   really want to tie their hands, you want to let them go as far as
   they can with the language they&#39;ve got. If you have tens of thousands
   of programmers, you would like everyone to not do anything
   interesting at all, to use the most basic of design patterns, to
   never optimize their code because it get&#39;s harder for the person
   whose behind them or they might make a mistake during optimisation.
&lt;/blockquote&gt;

&lt;p&gt;
Raymond Hettinger (via &lt;a href=&#34;http://radiofreepython.com/episodes/3/&#34;&gt;Radio Free Python&lt;/a&gt;)
&lt;/p&gt;

&lt;blockquote&gt;
Genius is one percent inspiration, ninety-nine percent perspiration.
&lt;/blockquote&gt;

&lt;p&gt;
Thomas Edison (via Linus Torvalds &lt;a href=&#34;http://www.youtube.com/watch?v=MShbP3OpASA&#34;&gt;Aalto talk&lt;/a&gt;)
&lt;/p&gt;

&lt;blockquote&gt;
Yes, I really like Python, I like it for a very specific reason, I
   like Python because of all the languages I have ever used it is the
   one that maximises ease of long term maintainability. That is the
   ease with which you can read your code six months later, and the
   longer I program the more convinced I am that that is &lt;b&gt;the&lt;/b&gt; most
   important metric of a language..  &lt;i&gt;bar none&lt;/i&gt;.
&lt;/blockquote&gt;

&lt;p&gt;
Eric &#39;ESR&#39; Raymond &lt;a href=&#34;http://youtu.be/1b17ggwkR60&#34;&gt;presenting to the Philadelphia Area Java Users&#39;
Group&lt;/a&gt;
&lt;/p&gt;

&lt;blockquote&gt;
The cheapest, fastest and most reliable components of a computer system are those that aren&#39;t there.
&lt;/blockquote&gt;

&lt;p&gt;
Gordon Bell (via Jon Bentley&#39;s - &lt;a href=&#34;http://www.amazon.co.uk/Programming-Pearls-ACM-Press-Bentley/dp/0201657880&#34;&gt;Programming Pearls&lt;/a&gt;)
&lt;/p&gt;

&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2012/&#34; title=&#34;2012&#34;&gt;2012&lt;/a&gt; /
&lt;a href=&#34;/2012/6/&#34; title=&#34;6&#34;&gt;6&lt;/a&gt; /
&lt;a href=&#34;/2012/6/25/&#34; title=&#34;25&#34;&gt;25&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-11-03T21:32:30Z</updated></entry><entry><title>Test driven development with Django</title><link href="/2011/11/17"/><id>/2011/11/17</id><content type="html">

&lt;article&gt;&lt;div class=&#34;entry&#34;&gt;&lt;h1&gt;Test driven development with Django&lt;/h1&gt;


&lt;p&gt;&lt;em&gt;2011-11-17&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;
I went to a &lt;a href=&#34;http://skillsmatter.com/podcast/ajax-ria/tdd-django-selenium/js-2958&#34;&gt;workshop&lt;/a&gt; last night on TDD (&lt;a href=&#34;http://en.wikipedia.org/wiki/Test-driven_development&#34;&gt;Test Driven Development&lt;/a&gt;)
using &lt;a href=&#34;https://www.djangoproject.com/&#34;&gt;django&lt;/a&gt; and &lt;a href=&#34;http://seleniumhq.org/&#34;&gt;selenium&lt;/a&gt;, which was given by &lt;a href=&#34;http://harry.pythonanywhere.com/&#34;&gt;Harry Percival&lt;/a&gt;.
It was hosted at &lt;a href=&#34;http://skillsmatter.com/go/find-us/js-1520&#34;&gt;skills matter exchange&lt;/a&gt; in London and there was free
beer and pizza…which was an unexpected bonus!
&lt;/p&gt;

&lt;p&gt;
There must have been around 35 attendees with a mixture of skill sets
and backgrounds and it was an extremely good introduction not only to
TDD but also to django framework, and almost everyone kept pace and I
was impressed by Harry&#39;s enthusiasm for TDD and why you should be
adopting it for development.
&lt;/p&gt;

&lt;p&gt;
I also think it highlighted the accessibility of the &lt;a href=&#34;https://www.djangoproject.com/&#34;&gt;django framework&lt;/a&gt;
and how you can pick up on it very quickly, and half way through the
pace was picked up as everyone in the room was generally flying though
the work. The workshop was based on the django tutorial &lt;a href=&#34;https://docs.djangoproject.com/en/dev/intro/tutorial01/&#34;&gt;writing my first app&lt;/a&gt; which leads you through from starting a project to creating
a polls application, which you can administer through the admin
interface and is a gentle introduction to the &lt;a href=&#34;https://docs.djangoproject.com/en/dev/faq/general/#django-appears-to-be-a-mvc-framework-but-you-call-the-controller-the-view-and-the-view-the-template-how-come-you-don-t-use-the-standard-names&#34;&gt;models / templates / view&lt;/a&gt; paradigm adopted by django.
&lt;/p&gt;

&lt;p&gt;
So you go from installing and setting up a basic django project and
application to firing up selenium to check each step of your progress
along the way.
&lt;/p&gt;

&lt;p&gt;
The key thing that I took away from it was the &lt;i&gt;develop - test - develop
- test&lt;/i&gt; loop that you need to cycle through, in order to be really TDD,
the tests direct &lt;i&gt;all&lt;/i&gt; development, so the steps are small and
incremental. Even though you know creating a models.py file with an
model class that doesn&#39;t even extend from django.db.models.Model, you do
&lt;i&gt;just&lt;/i&gt; enough to pass the next step of the test. Which should end up
with you not developing unnecessary code, which can happen when you are
developing without tests and you try to cover all possibilities without
thinking about what the application will &lt;i&gt;actually&lt;/i&gt; deliver upon. You
design your tests up front which you then write code to pass each
step/test along the way. Write a test that fails, write the code to make
it pass.
&lt;/p&gt;

&lt;p&gt;
You can follow all this along simply by going to &lt;a href=&#34;http://harry.pythonanywhere.com/&#34;&gt;Harry&#39;s website&lt;/a&gt;, I
recommended you do if you are interested in trying TDD and preferably
with the django framework, this is really aimed at everyone and so no
experience is necessary.
&lt;/p&gt;

&lt;p&gt;
Well done to harry for delivering such a good introduction on TDD with
django and selenium! There could be more workshops lined up, so if your
in London and fancy coming along, check the &lt;a href=&#34;http://mail.python.org/mailman/listinfo/python-uk&#34;&gt;python-uk mailing list&lt;/a&gt; to
see when any future workshops are planned.
&lt;/p&gt;


&lt;p class=&#34;datestamp&#34;&gt;&lt;a href=&#34;/&#34;&gt;Simons blog&lt;/a&gt; /
&lt;a href=&#34;/2011/&#34; title=&#34;2011&#34;&gt;2011&lt;/a&gt; /
&lt;a href=&#34;/2011/11/&#34; title=&#34;11&#34;&gt;11&lt;/a&gt; /
&lt;a href=&#34;/2011/11/17/&#34; title=&#34;17&#34;&gt;17&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/article&gt;

</content><updated>2022-11-03T21:20:16Z</updated></entry></feed>