<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Nick Craig-Wood&#39;s home page</title>
    <link>https://www.craig-wood.com/nick/</link>
    <description>Nick Craig-Wood&#39;s Home Page</description>
    <language>en-US</language>
    <copyright>Copyright (c) 1994-2026, Nick Craig-Wood; all rights reserved.</copyright>
    <atom:link href="https://www.craig-wood.com/nick/index.xml" rel="self" type="application/rss+xml" />
    <lastBuildDate>Thu, 25 Dec 2025 00:00:00 +0000</lastBuildDate>
    <item>
      <title>Xmas 2025</title>
      <link>https://www.craig-wood.com/nick/xmas/2025/</link>
      <pubDate>Thu, 25 Dec 2025 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2025/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2025]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2025 has been a year of courses, A-levels and a building project.&lt;/p&gt;
&lt;p&gt;Highlights include: a cookery course for Loveday and Nick at River Cottage; skiing in Kitzbühel; hosting Britney from Nanjing; a (baffling to some) visit to the Minecraft experience for Dougal’s 18th birthday; a party to celebrate the end of school; a fantastic family holiday in Sardinia with Loveday’s siblings scattered around Porto Rafael in seaside villas; a holiday with uni friends in Cornwall; the start of the renovations at The Mill and a crochet holiday in Morocco for Loveday.&lt;/p&gt;
&lt;p&gt;Amy is doing well at her work at The Land App when she can spare time between holidays and van adventures with her boyfriend Sam and Oggy (her dog). She bravely drove her van to Sardinia stopping off for climbing in Fontainebleau with Doug.&lt;/p&gt;
&lt;p&gt;Ed is still working with Nick. He and Phoebe (who is making an appearance in the card for the first time) have just celebrated 5 years together. They moved out of Guildford in the summer into their own flat in London, even taking most of their stuff with them.&lt;/p&gt;
&lt;p&gt;Issy finished her degree – hooray! As Ed moved out of the flat above the garage, Issy moved in. She is now taking some time off to think about what she is doing next.&lt;/p&gt;
&lt;p&gt;Dougal did a lot of studying sitting in the corner in Nick’s office. He got an excellent set of A-levels and has applied to study Computer Science at university next year. He had a great trip to the US with his cousin Olly and is now also working for Nick writing software. He still finds plenty of time to shout at his computer while gaming with his friends.&lt;/p&gt;
&lt;p&gt;Loveday and Nick have been enjoying swimming together a couple of times a week and having more time to walk the coast path in Cornwall. As we did last year, we travelled to Sardinia on the train enjoying time in Paris and Lake Como which was very special. Loveday vetoed all the pictures of her looking like a beetroot after we climbed to Brunate so you’ll just have to imagine it.&lt;/p&gt;
&lt;p&gt;Loveday has been extremely busy this year with Quakers, various courses (gardening, Alpha, agroforestry), and the start of work at The Mill. Nick has given up trying to remember where she is.&lt;/p&gt;
&lt;p&gt;Nick has had a good year having a lot of fun working with the boys. The business has exceeded expectations. He has been having fun with recreational maths (&lt;a href=&#34;https://arxiv.org/abs/2508.08307&#34;&gt;arXiv 2508.08307&lt;/a&gt;) discovering an great new formula for Pi!&lt;/p&gt;
&lt;p&gt;In October Loveday demolished The Mill. It was nice knowing it. What remains of it is floating in a sea of mud with a few builders mixed in. Or that is what Nick understands since he refuses to come and visit due to the fear of getting stuck in the mire. Hopefully it will get put back together some time next year.&lt;/p&gt;
&lt;img src=&#34;pi-arctan-formulae.png&#34; alt=&#34;Pi Formulae&#34; class=&#34;center&#34; width=&#34;400&#34; /&gt;
</description>
    </item>
    <item>
      <title>Unicode Block-Style Morse Encoder</title>
      <link>https://www.craig-wood.com/nick/radio/block_morse/</link>
      <pubDate>Tue, 12 Aug 2025 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/radio/block_morse/</guid>
      <description>&lt;style&gt;
  fieldset { border: 1px solid #3b4261; border-radius: 8px; padding: 1rem; }
  label { display: block; font-weight: 600; margin-bottom: 0.25rem; }
  #input { width: 100%; padding: 0.5rem; font-size: 1rem; background: #1f2335; color: #c0caf5; border: 1px solid #3b4261; border-radius: 4px; }
  #output { width: 100%; height: 260px; padding: 0.5rem; background: #1f2335; color: #c0caf5; border: 1px solid #3b4261; border-radius: 4px; }
  .buttons { margin-top: 0.5rem; display: flex; gap: 0.5rem; }
  .buttons button { padding: 0.5rem 0.8rem; border-radius: 8px; border: 1px solid #3b4261; background: #24283b; color: #c0caf5; cursor: pointer; }
  .buttons button:hover { background: #3b4261; }
  .buttons button:active { transform: translateY(1px); }
  .help { margin-top: 1rem; font-size: 0.95rem; }
  @media (prefers-color-scheme: light) {
    fieldset { border-color: #e7e5e4; }
    #input, #output { background: #f3f2ef; color: #1c1917; border-color: #e7e5e4; }
    .buttons button { background: #f3f2ef; color: #1c1917; border-color: #e7e5e4; }
    .buttons button:hover { background: #e7e5e4; }
  }
&lt;/style&gt;

&lt;fieldset&gt;
  &lt;label for=&#34;input&#34;&gt;Text&lt;/label&gt;
  &lt;input id=&#34;input&#34; type=&#34;text&#34; placeholder=&#34;Type text, e.g. SOS&#34; autocomplete=&#34;off&#34; /&gt;
  &lt;div class=&#34;buttons&#34;&gt;
    &lt;button id=&#34;convert&#34;&gt;Convert ⏎&lt;/button&gt;
    &lt;button id=&#34;clear&#34; type=&#34;button&#34;&gt;Clear&lt;/button&gt;
  &lt;/div&gt;
&lt;/fieldset&gt;

&lt;div class=&#34;help&#34;&gt;
  &lt;p&gt;&lt;strong&gt;How:&lt;/strong&gt; Type text and press &lt;kbd&gt;Enter&lt;/kbd&gt; or &lt;em&gt;Convert&lt;/em&gt;. Each conversion appends to the output below. Unsupported characters are skipped.&lt;/p&gt;
  &lt;p&gt;Output uses special block characters (U+1FB03, U+1FB0B) and spaces (U+2001) so it stays properly spaced in both mono and proportional fonts.&lt;/p&gt;
&lt;/div&gt;

&lt;label for=&#34;output&#34; style=&#34;display:block;margin-top:1rem;font-weight:600;&#34;&gt;Output&lt;/label&gt;
&lt;textarea id=&#34;output&#34; readonly&gt;&lt;/textarea&gt;

&lt;script&gt;
(() =&gt; {
  &#34;use strict&#34;;

  // Unicode block glyphs
  const DOT  = &#34;🬃&#34;;      // U+1FB03 (2 dits)
  const DASH = &#34;🬋🬃&#34;;     // U+1FB0B + U+1FB03 (4 dits)
  const EN   = &#34;\u2001&#34;;  // U+2001 EM QUAD SPACE (2 dits)

  // ITU Morse (A–Z, 0–9, basic punctuation)
  const MORSE = {
    &#39;A&#39;: &#39;.-&#39;,    &#39;B&#39;: &#39;-...&#39;,  &#39;C&#39;: &#39;-.-.&#39;,  &#39;D&#39;: &#39;-..&#39;,   &#39;E&#39;: &#39;.&#39;,
    &#39;F&#39;: &#39;..-.&#39;,  &#39;G&#39;: &#39;--.&#39;,   &#39;H&#39;: &#39;....&#39;,  &#39;I&#39;: &#39;..&#39;,    &#39;J&#39;: &#39;.---&#39;,
    &#39;K&#39;: &#39;-.-&#39;,   &#39;L&#39;: &#39;.-..&#39;,  &#39;M&#39;: &#39;--&#39;,    &#39;N&#39;: &#39;-.&#39;,    &#39;O&#39;: &#39;---&#39;,
    &#39;P&#39;: &#39;.--.&#39;,  &#39;Q&#39;: &#39;--.-&#39;,  &#39;R&#39;: &#39;.-.&#39;,   &#39;S&#39;: &#39;...&#39;,   &#39;T&#39;: &#39;-&#39;,
    &#39;U&#39;: &#39;..-&#39;,   &#39;V&#39;: &#39;...-&#39;,  &#39;W&#39;: &#39;.--&#39;,   &#39;X&#39;: &#39;-..-&#39;,  &#39;Y&#39;: &#39;-.--&#39;,
    &#39;Z&#39;: &#39;--..&#39;,
    &#39;0&#39;: &#39;-----&#39;, &#39;1&#39;: &#39;.----&#39;, &#39;2&#39;: &#39;..---&#39;, &#39;3&#39;: &#39;...--&#39;, &#39;4&#39;: &#39;....-&#39;,
    &#39;5&#39;: &#39;.....&#39;, &#39;6&#39;: &#39;-....&#39;, &#39;7&#39;: &#39;--...&#39;, &#39;8&#39;: &#39;---..&#39;, &#39;9&#39;: &#39;----.&#39;,
    &#39;.&#39;: &#39;.-.-.-&#39;, &#39;,&#39;: &#39;--..--&#39;, &#39;?&#39;: &#39;..--..&#39;, &#34;&#39;&#34;: &#39;.----.&#39;,
    &#39;!&#39;: &#39;-.-.--&#39;, &#39;/&#39;: &#39;-..-.&#39;, &#39;(&#39;: &#39;-.--.&#39;, &#39;)&#39;: &#39;-.--.-&#39;,
    &#39;&amp;&#39;: &#39;.-...&#39;,  &#39;:&#39;: &#39;---...&#39;, &#39;;&#39;: &#39;-.-.-.&#39;, &#39;=&#39;: &#39;-...-&#39;,
    &#39;+&#39;: &#39;.-.-.&#39;,  &#39;-&#39;: &#39;-....-&#39;, &#39;_&#39;: &#39;..--.-&#39;, &#39;&#34;&#39;: &#39;.-..-.&#39;,
    &#39;$&#39;: &#39;...-..-&#39;,&#39;@&#39;: &#39;.--.-.&#39;
  };

  const encodeSymbol = sym =&gt; (sym === &#39;.&#39;) ? DOT : DASH;

  const encodeLetter = ch =&gt; {
    const pat = MORSE[ch.toUpperCase()];
    if (!pat) return &#39;&#39;;
    const symbols = [...pat].map(encodeSymbol).join(&#39;&#39;);
    return symbols + EN; // add 2‑dit spacing at the end of the letter
  };

  const textToBlockMorse = text =&gt; {
    const parts = [];
    const words = text.split(&#39; &#39;);
    for (const word of words) {
      for (const letter of word) {
        const enc = encodeLetter(letter);
        if (enc) parts.push(enc);
      }
      // word gap = 7 dits; we already have 3, so add 4 more (2 × EN)
      parts.push(EN + EN);
    }
    return parts.join(&#39;&#39;);
  };

  // UI wiring
  const $in  = document.getElementById(&#39;input&#39;);
  const $out = document.getElementById(&#39;output&#39;);
  const $convert = document.getElementById(&#39;convert&#39;);
  const $clear   = document.getElementById(&#39;clear&#39;);

  const appendOutput = str =&gt; {
    if (!str) return;
    $out.value += ($out.value ? &#34;\n&#34; : &#34;&#34;) + str;
    $out.scrollTop = $out.scrollHeight;
  };

  const handleConvert = () =&gt; {
    const raw = $in.value.trim();
    if (!raw) return;
    const encoded = textToBlockMorse(raw);
    appendOutput(encoded);
    $in.value = &#39;&#39;;
    $in.focus();
  };

  $convert.addEventListener(&#39;click&#39;, handleConvert);
  $clear.addEventListener(&#39;click&#39;, () =&gt; { $out.value = &#39;&#39;; $in.focus(); });

  // Enter submits (Shift+Enter to insert a newline if needed)
  $in.addEventListener(&#39;keydown&#39;, e =&gt; {
    if (e.key === &#39;Enter&#39; &amp;&amp; !e.shiftKey) {
      e.preventDefault();
      handleConvert();
    }
  });
})();
&lt;/script&gt;
</description>
    </item>
    <item>
      <title>Xmas 2024</title>
      <link>https://www.craig-wood.com/nick/xmas/2024/</link>
      <pubDate>Wed, 25 Dec 2024 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2024/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2024]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve enjoyed time at home in 2024 with plenty of lunches with the boys as Ed is working with Nick and Doug usually drops in for his lunch hour. Highlights of the year have included: a ski trip to Andorra with Loveday&#39;s brother and Doug&#39;s cousins; quality time for Loveday getting muddy at The Mill and planting 300 trees; hosting two Chinese students from Nanjing, Albert and Alice; an Easter trip to Cornwall with friends and family; celebrating our 30th wedding anniversary with a stay at The Pig on the Beach in perfect weather; seeing &lt;a href=&#34;https://www.cornwalllive.com/news/cornwall-news/blue-plaque-helps-commemorate-quaker-9411030&#34;&gt;Loveday Hambly&lt;/a&gt;&#39;s (Loveday&#39;s famous Quaker namesake) blue plaque being unveiled at Tregongeeves in Cornwall; and attending an Emmanuel College re-union.&lt;/p&gt;
&lt;p&gt;Our big adventure of the year was a summer holiday in Sardinia. The family wanted to do watersports in the sun – but Loveday refused to fly. How to square that circle? Loveday and Nick took the train, stopping off in Paris, Milan and Florence, spent 2 weeks by the sea with the family, and then returned via Pisa, Genova, Ventimiglia and Nice. The train journeys bookending the trip made it very memorable holiday.&lt;/p&gt;
&lt;p&gt;Amy started the year travelling while the grand-puppy (Oggy) stayed at Fairholme. In May she joined The Land App as a digital designer after a longer-than-expected gap. She works a nine day fortnight leaving time for adventures in her converted van accompanied by Oggy and her boyfriend, Jake.&lt;/p&gt;
&lt;p&gt;Ed has been helping Dad with the business side of &lt;a href=&#34;https://rclone.com/&#34;&gt;Rclone Services&lt;/a&gt; when he can fit it in between learning and filming skateboard tricks and sleeping. He had a great interrailling trip with Phoebe visiting eastern Europe and skateboarding with his mates in Prague and Poland. Dad is getting him an alarm clock for Christmas.&lt;/p&gt;
&lt;p&gt;Issy is in her third year at uni studying liberal arts, for some definition of studying at least. She hasn&#39;t been in the best of health this year but she is happier in her new flat. She enjoyed visiting her friend Emily in New York and won a poetry competition with her poem &lt;a href=&#34;https://poems.poetrysociety.org.uk/poets/issy-craig-wood/&#34;&gt;Love Can Give You This Cool Shark (Journal Entry)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dougal&#39;s deep in Year 13 now, grinding hard on his skateboard, CompSci and Electronics projects. Man&#39;s fully locked in for his A-levels. He&#39;d say I&#39;m glazing him, but trust me - bro&#39;s gonna get the W.&lt;/p&gt;
&lt;p&gt;Nick has been busy this year with his new business. All good fun though – writing open source software and supporting paying customers is a nice change of pace and much less stressful than previous enterprises. In his spare moments he has been accumulating half-completed maths, radio, software and electronics projects.&lt;/p&gt;
&lt;p&gt;Loveday at last decided on a design for The Mill and we got planning permission! Whether it will get built anytime soon is a different matter. She and Issy volunteered on the children&#39;s program at Quaker BYM. She has also been very busy with local Quakers, Zero Carbon Guildford and her pesky family always wanting things!&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Xmas 2023</title>
      <link>https://www.craig-wood.com/nick/xmas/2023/</link>
      <pubDate>Mon, 25 Dec 2023 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2023/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2023]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2023 has seen lots of foreign travel for everyone except Loveday. It
started with Amy leaving for Dubai, South Africa and Senegal. Nick,
Ed, Phoebe (Ed’s girlfriend) and Dougal went on the ski train to
France and enjoyed a week of late season skiing - with no broken
bones!&lt;/p&gt;
&lt;p&gt;Nick, Issy and Dougal had a spectacular trip to Japan in the summer
for wonderful food, toilets, sights, cleanliness, trains, Anime and
cheap amateur radio equipment. It was very hot though! We finished the
trip with 3 days in Korea and ate lots of delicious barbecued meats,
fried food and desserts.&lt;/p&gt;
&lt;p&gt;Trips to The Mill in Cornwall: lots, number of redesigns considered:
→∞, number of designs finalized: 0, number of things decided: NaN.&lt;/p&gt;
&lt;p&gt;The children remain alive, but one year older ignoring relativistic
time dilation effects due to the travelling.&lt;/p&gt;
&lt;p&gt;Amy has had a busy year converting her van, travelling, surfing,
climbing and working at Olio. Sadly Olio seem to be running out of
runway so Amy was made redundant in November. She immediately booked
her dog into the dog sitters (us!) and a flight to Sri Lanka for 3
weeks of surfing in January!&lt;/p&gt;
&lt;p&gt;Ed started the year as an advisor for Reassured but decided to come
and work with Dad for a few months (while making skateboard videos on
the side) before setting off travelling with Phoebe for 3 months round
SE Asia, Australia and NZ.&lt;/p&gt;
&lt;p&gt;Issy is in her second year at uni studying liberal arts (a bit like
literary arts with a helping of TV studies). When not working she has
been helping out with the children at Quaker meeting. She has taken up
a troglodyte existence in a basement in Archway and would love a visit
if you don’t mind the fungus!&lt;/p&gt;
&lt;p&gt;Dougal got an excellent set of GCSEs and has started at a local school
for 6th form. At last, after 23 years, Loveday is free of school runs!
Dougal is doing Maths, Further Maths, More Maths and Even More Maths
(disguised as Computer Science and Electronics). He is also doing a
lot of climbing (rocks rather than social).&lt;/p&gt;
&lt;p&gt;Nick had a paper published on his Pi obsession (&lt;a href=&#34;https://scholarlycommons.pacific.edu/euleriana/vol3/iss1/3/&#34;&gt;Euler found the first
binary digit extraction formula for π in 1779&lt;/a&gt;) so
can concentrate on other stuff finally! He also set up a little
company &lt;a href=&#34;https://rclone.com/&#34;&gt;Rclone Services Ltd&lt;/a&gt; to run support
contracts for his open source software. Ed has been very useful
helping with sales and marketing.&lt;/p&gt;
&lt;p&gt;Loveday has monetised Nick this year giving him the push to set up his
new company. With her new found free time she’s been knitting at 44.7
ms⁻¹. She has also has become the treasurer of Guildford Quaker
Meeting, been volunteering at &lt;a href=&#34;https://www.zerocarbonguildford.org/&#34;&gt;Zero Carbon Guildford&lt;/a&gt;
and demonstrating for the climate and peace.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Infinity mirror with Raspberry Pi Pico, Neopixels and Micropython</title>
      <link>https://www.craig-wood.com/nick/articles/infinity-mirror/</link>
      <pubDate>Sat, 11 Feb 2023 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/articles/infinity-mirror/</guid>
      <description>&lt;h1 id=&#34;infinity-mirror-with-raspberry-pi-pico-neopixels-and-micropython&#34;&gt;Infinity mirror with Raspberry Pi Pico, Neopixels and Micropython&lt;/h1&gt;
&lt;p&gt;Here is an account of how I renovated our old infinity mirror to this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;mirror.gif&#34; alt=&#34;Animated GIF of mirror&#34;&gt;&lt;/p&gt;
&lt;p&gt;From this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;before.jpg&#34; alt=&#34;Mirror before&#34;&gt;&lt;/p&gt;
&lt;p&gt;This isn&#39;t a recipe on how to do this yourself (though you could
certainly use it like that), its an account of exactly what I did,
including all the bits where I wasn&#39;t sure where I was going in the
hope it will help less experienced constructors with the thought
process.&lt;/p&gt;
&lt;h2 id=&#34;the-mirror&#34;&gt;The mirror&lt;/h2&gt;
&lt;p&gt;A long time ago my wife and I were looking in a lighting shop and we
came across the infinity mirror. I was immediately captivated by it
and we had it installed in our bathroom when we had it renovated.&lt;/p&gt;
&lt;p&gt;Fast forward more than a decade and the lights in the infinity mirror
had stopped working. I had never taken it apart to see how to fix it
which I really should have done but you know how you get used to
things not working...&lt;/p&gt;
&lt;p&gt;Just before Christmas 2022 I decided I would like to have a project to
work on over the holiday period, so after a very brief bit of
research I ordered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;40 plated through hole neopixel LEDs&lt;/li&gt;
&lt;li&gt;2 raspberry pi pico W microcontrollers&lt;/li&gt;
&lt;li&gt;5V 2A PSU&lt;/li&gt;
&lt;li&gt;40 x 330uF capacitors&lt;/li&gt;
&lt;li&gt;40 x 330Ohm resistors&lt;/li&gt;
&lt;li&gt;Some more wire since I had run out&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I chose the plated through LED style neopixels because I knew they&#39;d
be visible in the mirror and I wanted them to look nicer than the
neopixel strips. I knew I needed 34 LEDs but I ordered some extra for
testing. I ended up breaking a couple of them so just as well.&lt;/p&gt;
&lt;p&gt;I chose the pi pico because I&#39;d done a project with that before with
C++ but I thought it would be fun to try micropython (which I hadn&#39;t
tried before).&lt;/p&gt;
&lt;p&gt;The resistors and caps I chose after a bit of looking at the
datasheet. Spoiler - I didn&#39;t need these in the end and I did need
some decoupling caps instead - see later.&lt;/p&gt;
&lt;p&gt;I made that order in the full knowledge that it wouldn&#39;t be everything
I needed and that there may be stuff in there that I didn&#39;t need. When
getting going on a project its much more important for me to make a
start even if it is in the wrong direction than to wait until I&#39;ve
planned everything out to the last degree.&lt;/p&gt;
&lt;p&gt;Later I ended up ordering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;40 x 10nF ceramic capacitors&lt;/li&gt;
&lt;li&gt;50 x bezel mounts for the 5mm LEDs&lt;/li&gt;
&lt;li&gt;5 x 100k pots with nice knobs&lt;/li&gt;
&lt;li&gt;5 x switches&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;neopixels&#34;&gt;Neopixels&lt;/h3&gt;
&lt;p&gt;Once the stuff arrived I took some photos to see how the neopixels
worked inside.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;neopixel-from-top.jpg&#34; alt=&#34;crop of neopixel from top&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;neopixel-from-side.jpg&#34; alt=&#34;crop of neopixel from side&#34;&gt;&lt;/p&gt;
&lt;p&gt;You can see the 3 LED chips and also the controller chip all connected
together with very fine wire in the LED encapsulation.&lt;/p&gt;
&lt;p&gt;Neopixels have 4 connections, &lt;code&gt;Volts&lt;/code&gt;, &lt;code&gt;Ground&lt;/code&gt;, &lt;code&gt;Data In&lt;/code&gt; and &lt;code&gt;Data Out&lt;/code&gt;. You chain them up &lt;code&gt;Data In&lt;/code&gt; to &lt;code&gt;Data Out&lt;/code&gt; and you connect the
first &lt;code&gt;Data In&lt;/code&gt; to your microcontroller (in this case a Raspberry Pi
Pico). The microcontroller generates a serial data stream with 24 bit
color for each neopixel. The first neopixel uses the first block of
pixel data to color itself and passes the rest of the stream on. This
means you can chain hundreds of them together with only one pin on
your microcontroller and address each one individually.&lt;/p&gt;
&lt;h2 id=&#34;neopixels-and-micropython&#34;&gt;Neopixels and micropython&lt;/h2&gt;
&lt;p&gt;The first thing I wanted to do was to make a neopixel work from
micropython to give me some confidence that the project would work.&lt;/p&gt;
&lt;p&gt;I made a plan like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install micropython on the pi pico and make it work&lt;/li&gt;
&lt;li&gt;Breadboard a single neopixel to see if that works&lt;/li&gt;
&lt;li&gt;Breadboard a chain of neopixels to see if they work&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I fully expected these steps to be very hard - bringing up new
hardware is always troublesome.&lt;/p&gt;
&lt;h3 id=&#34;installing-micropython&#34;&gt;Installing micropython&lt;/h3&gt;
&lt;p&gt;Installing micropython turned out to be very easy. I installed the
micropython firmware from here&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.raspberrypi.com/documentation/microcontrollers/micropython.html&#34;&gt;https://www.raspberrypi.com/documentation/microcontrollers/micropython.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Using Pico W version &lt;code&gt;rp2-pico-w-20230116-unstable-v1.19.1-803-g1583c1f67.uf2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I then needed to work out how to communicate with micropython. I tried
&lt;code&gt;thonny&lt;/code&gt; but I don&#39;t really like graphical clicky GUIs and eventually
I found that Ubuntu packaged &lt;code&gt;rshell&lt;/code&gt; which worked and let me use a
REPL on the board and transfer files into the flash.&lt;/p&gt;
&lt;p&gt;This was so easy compared to microcontroller development I&#39;ve done in
the past - well done Raspberry Pi and Micropython.&lt;/p&gt;
&lt;p&gt;Having a REPL on the board meant I could do little experiments to see
if bits of hardware were working just by typing python snippets.&lt;/p&gt;
&lt;h3 id=&#34;first-light&#34;&gt;First light&lt;/h3&gt;
&lt;p&gt;I soldered on 7 pins to the pico (just enough for power, IO and to
stop it wobbling) then I plugged it into a breadboard with a single
neopixel.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;single-neopixel.jpg&#34; alt=&#34;single neopixel breadboard&#34;&gt;&lt;/p&gt;
&lt;p&gt;It took me a little while to discover that there is a built in
neopixel library in the pico micropython. I found an external library
first but decided to use the built in library after evaluating it.&lt;/p&gt;
&lt;p&gt;I could then use the REPL from &lt;code&gt;rshell&lt;/code&gt; to write code and try to make
neopixel work.&lt;/p&gt;
&lt;p&gt;This should set the LED to a pink color:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; neopixel &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; NeoPixel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; machine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pin &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; machine&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Pin(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pixels &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; NeoPixel(pin, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pixels&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fill((&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pixels&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;write()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However it didn&#39;t set it to pink at all! Eventually I worked out that
the ordering of RGB seems to be wrong. I looked in the source for the
neopixel python library and saw I could fix it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NeoPixel&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ORDER &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So a test of the LED became:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; neopixel &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; NeoPixel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NeoPixel&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ORDER &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; machine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pin &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; machine&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Pin(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pixels &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; NeoPixel(pin, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pixels&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fill((&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pixels&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;write()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It was a relief to get over that hurdle - it seemed then that the
project might work after all.&lt;/p&gt;
&lt;h3 id=&#34;fifth-light&#34;&gt;Fifth light&lt;/h3&gt;
&lt;p&gt;I then extended the breadboard with 4 more neopixels for 5 in total
and tried to make that work.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;five-neopixels.jpg&#34; alt=&#34;5 neopixels&#34;&gt;&lt;/p&gt;
&lt;p&gt;I then had fun noodling around with python to try to make some
interesting patterns.&lt;/p&gt;

&lt;video autoplay loop muted playsinline style=&#34;max-width:100%; border-radius: 8px;&#34;&gt;
  &lt;source src=&#34;five-neopixels-lightshow.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;

&lt;p&gt;Note that the neopixels are extremely bright when on full power so I
did most of this testing with a bit of white paper over the neopixels.
When the neopixels are in the mirror they will shine sideways not
towards the viewer to make interesting internal reflections. This
worked out very well.&lt;/p&gt;
&lt;h3 id=&#34;knobs&#34;&gt;Knobs&lt;/h3&gt;
&lt;p&gt;At this point I realised it would be nice if the user had some control
over the display. A brightness knob at minimum would be nice!&lt;/p&gt;
&lt;p&gt;The Pico has 3 ADC pins so I bought some 100k pots with knobs off eBay
and wired them up and soldered them to the pico.&lt;/p&gt;

&lt;video autoplay loop muted playsinline style=&#34;max-width:100%; border-radius: 8px;&#34;&gt;
  &lt;source src=&#34;knobs.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;

&lt;p&gt;Later I discovered that 100k was too big a value as they are a bit
noisy and can&#39;t quite pull up and down to the rails due to the
internal resistance of the pico ADC. I chose the 100k to save a bit of
power but it was a mistake - 10k pots would have been better. I left
them at 100k though and did a bit of work in the software to make sure
they could hit completely off and completely on.&lt;/p&gt;
&lt;p&gt;I also at this point decided to add two buttons for mode up and mode
down but I didn&#39;t make them until later.&lt;/p&gt;
&lt;h2 id=&#34;mechanical-work&#34;&gt;Mechanical work&lt;/h2&gt;
&lt;p&gt;Now that I had proved the concept of the pico and neopixels it was
time for me to disassemble the mirror. I really should have done this
before I started, but I guess I enjoy the feeling of not knowing what
I&#39;m doing ;-)&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;before.jpg&#34; alt=&#34;Mirror before&#34;&gt;&lt;/p&gt;
&lt;p&gt;You can see the mirror has what is essentially a string of Christmas
lights inside. These gave a beautiful creamy light so I hope I don&#39;t
destroy that with the LEDs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;inner-mirror.jpg&#34; alt=&#34;pic of inner of mirror&#34;&gt;&lt;/p&gt;
&lt;p&gt;Each Christmas light came out through a hole about 10mm in diameter
and I had to work out how to fit the LEDs which are 5mm in diameter
into those holes neatly. This is all very visible so it had to look
nice.&lt;/p&gt;
&lt;p&gt;This was probably the hardest part of the project for me. If I had a
3D printer I guess I could have printed something up.&lt;/p&gt;
&lt;p&gt;After a lot of messing about, I eventually bought some panel mounts
for the LEDs. This made them up to 8 mm in diameter. They were not
quite big enough and it took a lot of force to get the LEDs far enough
into the panel mounts. I broke a couple of LEDs doing it!&lt;/p&gt;
&lt;p&gt;Then I cut about 1cm off the end of all the Christmas lights (with a
saw!) so I could re-use the little bit of green plastic tube you see
below and put the panel mount into those which luckily fit perfectly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;leds-ready.jpg&#34; alt=&#34;LEDs ready for mounting&#34;&gt;&lt;/p&gt;
&lt;p&gt;At last the LEDs were ready to fit into the 10mm holes in the frame.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;leds-in-frame.jpg&#34; alt=&#34;pic of LEDs in the frame&#34;&gt;&lt;/p&gt;
&lt;p&gt;I then soldered the wires to connect up the neopixels. I also soldered
a 10nF decoupling capacitor across the power lines for each one. The
datasheet recommended feeding each one through a resistor with a
reservoir capacitor, but in my tests the 5V PSU I had bought was
plenty capable of dealing with the power surges so I just went for a
decoupling capacitor to minimise noise.&lt;/p&gt;
&lt;p&gt;This was a lot of soldering - it took about 4 hours to make and solder
all the wires. There are 3 wires for each LED that needed making and 4
solder joints, so 204 wire ends to strip and tin and 102 joints to
make with 3 or 4 things being soldered together!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;soldering.jpg&#34; alt=&#34;pic of soldering&#34;&gt;&lt;/p&gt;
&lt;p&gt;With the benefit of 20/20 hindsight and a bit more searching eBay and
Amazon I could have bought a string of Christmas light neopixels which
probably would have done the job with much less soldering.&lt;/p&gt;
&lt;p&gt;I then connected the breadboard and made sure the lights worked.&lt;/p&gt;
&lt;h2 id=&#34;software&#34;&gt;Software&lt;/h2&gt;
&lt;p&gt;Now the hardware unknowns were beaten for the moment it was time to
get back to the software.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&#34;https://github.com/ncw/mirror&#34;&gt;download the software from github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One thing I did do which I recommend you always do when working with
embedded stuff is write a simulator.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;simulator.png&#34; alt=&#34;screenshot of simulator&#34;&gt;&lt;/p&gt;
&lt;p&gt;I used pygame for this. This meant I could test and debug the display
modes on my desktop which was a much quicker cycle than testing on the
raspberry pi pico. It&#39;s also a nice thing to have - you can download
the code from the github repo and try it yourself even if you don&#39;t
have any hardware.&lt;/p&gt;
&lt;p&gt;I went through a few iterations of how exactly to split the code
between the simulator and micropython but in the end passing a
&lt;code&gt;mirror&lt;/code&gt; object to each mode turned out the easiest.&lt;/p&gt;
&lt;p&gt;I experimented with different frame rates and I found that 50 Hz was
too fast - some of the modes were dropping frames so I settled on 25
Hz.&lt;/p&gt;
&lt;p&gt;I also experimented with running the refresh off a timer interrupt in
micropython. This worked for a while and then locked up and I
conjecture I was doing too much on the interrupt. I switched it over
to a timed sleep and it became 100% reliable after that.&lt;/p&gt;
&lt;p&gt;I experimented with lots of different modes and had the idea of using
the board&#39;s temperature sensor for a temperature display mode and using
the on board WiFi to pick up the current time for a clock mode. The
clock mode actually works really well - with a few minutes&#39; practice you
can read it just like any analogue clock.&lt;/p&gt;
&lt;h2 id=&#34;final-assembly&#34;&gt;Final assembly&lt;/h2&gt;
&lt;p&gt;Now that the software was looking good I went back to the hardware
side for the final assembly.&lt;/p&gt;
&lt;p&gt;I needed to get the pico off the bread board and mounted into the mirror somehow.&lt;/p&gt;
&lt;p&gt;In the end I decided to make a piece of wood which I would velcro
underneath the mirror (there is a small gap so it won&#39;t be visible)
and put the pico and knobs there.&lt;/p&gt;

&lt;video autoplay loop muted playsinline style=&#34;max-width:100%; border-radius: 8px;&#34;&gt;
  &lt;source src=&#34;final-construction.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;

&lt;p&gt;This taxed my meagre carpentry skills. I made a mistake with the
knobs - the bit of wood I chose was too thick to put the nuts on the
knob shafts to hold them in which was a bit of a disaster. However I
decided to epoxy them and the buttons in place which made a nice
result provided I don&#39;t ever want to take them off again.&lt;/p&gt;
&lt;p&gt;I fed the power (5V, GND) in to the top of the mirror and out of the
bottom of the mirror comes 3 wires, 5V, GND and the input to the
string of neopixels. The 5V line goes via a diode to VSYS on the pico
so that the pico can be powered via the USB or by the external 5V PSU.
This arrangement is outlined in the datasheet for the pico.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;VBUS is the 5V input from the micro-USB port, which is fed through a
Schottky diode to generate VSYS. The VBUS to VSYS diode (D1) adds
flexibility by allowing power ORing of different supplies into VSYS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and later&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The simplest way to safely add a second power source to Pico is to
feed it into VSYS via another Schottky diode (see Figure 15). This
will &#39;OR&#39; the two voltages, allowing the higher of either the
external voltage or VBUS to power VSYS, with the diodes preventing
either supply from back-powering the other.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We will run the LEDs directly from an external 5V power supply. Since
the VSYS input range is 1.8V to 5.5V we don&#39;t need to worry about a
diode drop, so any silicon diode should be fine.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;So via a diode connect external 5V PSU to VSYS&lt;/li&gt;
&lt;li&gt;Leave VBUS unconnected (since it connects directly to the USB power)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This will allow us to connect a computer and not blow up the computer
with the external 5V PSU.&lt;/p&gt;
&lt;p&gt;The neopixel drive is connected to GP0 via a 330Ohm resistor. Why the
resistor? Just in case the pin gets shorted to 5V - that will save the
pico in that case.&lt;/p&gt;
&lt;p&gt;I made connectors for the 3 wires to the pico board so I could take it
off and things are very nearly done.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That was a lot of fun. The mirror is somewhat mesmerising in the color
cycling modes. It also made the wife happy to have the infinity mirror
working again, so win-win-win :-)&lt;/p&gt;

&lt;video autoplay loop muted playsinline style=&#34;max-width:100%; border-radius: 8px;&#34;&gt;
  &lt;source src=&#34;color-cycling.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;

&lt;h2 id=&#34;thanks&#34;&gt;Thanks&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Dougal for helping me with the wire stripping&lt;/li&gt;
&lt;li&gt;Dave Lawrence for writing the Matrix and ChaseRGB modes&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Xmas 2022</title>
      <link>https://www.craig-wood.com/nick/xmas/2022/</link>
      <pubDate>Sun, 25 Dec 2022 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2022/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2022]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We’d love to blame the lateness of this card on the postal strikes; in
reality it is because we have been even less organised than usual! We
hope you had a lovely Christmas and this reaches you in time for New
Year.&lt;/p&gt;
&lt;p&gt;2022 has been a relatively quiet year for us. Nick booked a ski trip
in March but unfortunately covid hit just before the trip so Ed,
Phoebe (Ed’s girlfriend) and Dougal went without him. Amazingly, they
came back in the same number of pieces that they went!&lt;/p&gt;
&lt;p&gt;In August, Nick, Loveday and Dougal took the ferry to northern Spain
where Issy and her friend Emily joined us after interrailling through
France and Spain. We stayed near A Coruña and enjoyed surfing and
exploring cities such as Santiago and Lugo, and the beautiful
coastline. The roads were excellent but Loveday was disappointed by
the endless eucalyptus plantations (for paper) which have replaced
much of the native flora.&lt;/p&gt;
&lt;p&gt;We’ve had several trips to The Mill in Cornwall, including Easter with
friends, where we went for walks along the cliff paths, worked on the
garden and made plans for future renovations.&lt;/p&gt;
&lt;p&gt;Amy (26) left Just Eat to join Olio as a UX Designer in a fully remote
job. She bought a new van and spent many happy hours converting it
into a camper and getting Dad to do the electrics before taking off to
Ireland for a fortnight. She’s currently a digital nomad on her way to
South Africa for 2 months, leaving Oggy behind.&lt;/p&gt;
&lt;p&gt;Ed (25) spent part of the year working for an outfit selling whiskey
barrels by the pallet and is about to start a job in Basingstoke as an
insurance protection adviser. He had a lovely holiday with Phoebe in
Canada.&lt;/p&gt;
&lt;p&gt;Issy (21) completed her Early Years Education course in June and had a
summer of fun, including Shambala Festival with Amy. She has survived
first term of university at King’s College London, studying Liberal
Arts.&lt;/p&gt;
&lt;p&gt;Dougal (15) has been enjoying skateboarding with Ed and his school
friends. He’s passed the 6th form entrance exam for his new school in
Guildford so will be able to walk to school – hooray. GCSEs first
though!&lt;/p&gt;
&lt;p&gt;Nick (M5NCW) built his first portable transceiver and used it to make
Morse code contacts in Europe while sitting in the garden in Cornwall.
Having been a fan of Formula 1 for many years it was a real treat to
attend the British Grand Prix for the first time to see an especially
eventful race. Nick continues to do consultancy and work on his rclone
project.&lt;/p&gt;
&lt;p&gt;Loveday started the year very busy with her postgraduate studies in
Ecology and Sustainability completing her diploma but deciding not to
do the master’s dissertation. She has been heavily involved in Quaker
activities including organising a weekend retreat. She loves meeting
up with her book group friends and volunteering at Zero Carbon
Guildford, where she helps run the community fridge.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Xmas 2021</title>
      <link>https://www.craig-wood.com/nick/xmas/2021/</link>
      <pubDate>Sat, 25 Dec 2021 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2021/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2021]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We had a very exciting end to 2020 as we completed the purchase of The
Mill in Port Isaac just before Christmas. Our new Cornish stronghold
is an old miller’s cottage and converted watermill. Our plan is to
move there in a few years but we are open for holidays now if you’d
like to visit.&lt;/p&gt;
&lt;p&gt;In March 2021 Pepper had a lovely multicoloured litter of 5 puppies.
Pepper and her puppies accompanied us on our first family visit to The
Mill as soon as lockdown lifted, the children having been unable to
visit before. Pepper was an excellent mother and the puppies have all
gone to friends and family, with Amy adopting Oggy (our first
grandpuppy!).&lt;/p&gt;
&lt;p&gt;In June we went on Holiday to Plockton in Scotland. The weather was
amazing for exploring the beautiful scenery. While there we met up
with old friends and Tristram and family. Dougal and his cousins had
lots of fun jumping into cold lochs.&lt;/p&gt;
&lt;p&gt;We decamped to Cornwall for most of the summer to explore our new
demesne. Lots of friends and family came to see us there – having new
visitors every week was great fun!&lt;/p&gt;
&lt;p&gt;Amy bought her first house in Bristol and moved in with Oggy and Ziggy
her red van. She is a UX designer for Just Eat and hangs out with the
‘Waves and Paves’ girls. Amy, boyfriend Sam, Oggy and Ziggy enjoyed
the NC 500 this summer.&lt;/p&gt;
&lt;p&gt;In March Ed moved out. He and his girlfriend Phoebe are renting a flat
together in Woking though he returns home regularly to raid the
fridge. Ed worked for Money Expert selling energy and broadband for
most of the year but now has a new challenge learning how to be a
financial adviser with Neilson Place.&lt;/p&gt;
&lt;p&gt;Issy has been doing the second year of her Early Years Education
course at Guildford College and has loved doing work experience in our
local nursery, pre-school and primary school. She has been having fun
with her new college friends and is looking forward to studying
Liberal Arts at university next year.&lt;/p&gt;
&lt;p&gt;Dougal has started his GCSE courses at school. Lockdown school went
much better this year, helped by a dedicated laptop (no games!) and
the school running live online lessons. He did his first overnight
adventure with the school for his Bronze DofE. When not at school he
enjoys gaming, surfing and skateboarding, both with and without his
big brother.&lt;/p&gt;
&lt;p&gt;In June Nick passed his Radio Amateur’s exam and now has the callsign
2E0WPM. At the Gophercon UK conference in October he gave a talk about
deadlocks which went very well. He’s been working on rclone and doing
software consultancy while taking time out to learn Morse Code, do
radio experiments and help Loveday make lots of Uncle Rick’s spicy
pickle!&lt;/p&gt;
&lt;p&gt;Loveday is continuing to do her Masters very slowly. She has been
getting The Mill ready to let, doing lots of Quaker related activities
including marching with her banner during COP26 and has been
volunteering with Zero Carbon Guildford.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Deadlocks: the dark side of concurrency</title>
      <link>https://www.craig-wood.com/nick/articles/deadlocks-in-go/</link>
      <pubDate>Mon, 25 Oct 2021 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/articles/deadlocks-in-go/</guid>
      <description>&lt;p&gt;This is a transcript of a talk I gave at Gophercon UK on 2021-10-25. You can &lt;a href=&#34;https://youtu.be/9j0oQkqzhAE&#34;&gt;watch it on YouTube&lt;/a&gt; (47 minutes) or see the slides and read the words here.&lt;/p&gt;
&lt;p&gt;Go makes it so easy to write concurrent programs that sooner or later you will run into a deadlock. A deadlock is where your program (or part of it) just stops working for mysterious reasons.&lt;/p&gt;
&lt;p&gt;This talk will explain what deadlocks are and why the Go deadlock detector isn&#39;t very useful in real world programs.&lt;/p&gt;
&lt;p&gt;Deadlocks can be very difficult to find and fix and this talk will give lots of tips on how to figure out why your program deadlocked and how to fix it and avoid deadlocks in the future.&lt;/p&gt;
&lt;p&gt;You will need an understanding of go routines, locking (sync.Mutex) and channels to get the most out of this talk. No previous deadlock experience required!&lt;/p&gt;
&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-01.png&#34; alt=&#34;Slide: Title - Deadlocks in Go&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Hello and welcome everyone.&lt;/p&gt;
&lt;p&gt;I’m Nick Craig-Wood and I’m going to be talking to you about deadlocks.&lt;/p&gt;
&lt;p&gt;This is an intermediate level talk, so I’m assuming you know what a go routine is and have some idea what a channel and a mutex is.&lt;/p&gt;
&lt;p&gt;I’ve put a link to the &lt;a href=&#34;https://github.com/ncw/go-deadlocks-talk&#34;&gt;code samples&lt;/a&gt; up there – you don’t need them as I’ll be putting them on the screen, but you can have them for reference during the talk or later.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-02.png&#34; alt=&#34;Slide: Talk overview&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;In this talk we are going to talk about what a deadlock is, how to debug them and how to avoid them in future.&lt;/p&gt;
&lt;p&gt;It will have lots of real world examples culled from dozens of painful examples in the &lt;a href=&#34;https://rclone.org&#34;&gt;rclone&lt;/a&gt; codebase!&lt;/p&gt;
&lt;p&gt;I learned about deadlocks the hard way by having to debug lots of them and I’m aiming of for this to be the talk I would have like to listened to when I knew nothing.&lt;/p&gt;
&lt;p&gt;Hopefully everyone, no matter how experienced will pick up a few tips.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-03.png&#34; alt=&#34;Slide: About me&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;But first a little bit about me. At the moment I’m mostly doing Open Source coding on &lt;a href=&#34;https://rclone.org&#34;&gt;rclone&lt;/a&gt; with a bit of consultancy.&lt;/p&gt;
&lt;p&gt;I’ve been using Go for 9 years since before version 1.0. I got into it when I was a busy CTO and found I was doing nearly 100% people management and strategy with no time for coding. So I decided I’d learn Go in my spare time because it sounded interesting and I needed a programming activity to keep me sane.&lt;/p&gt;
&lt;p&gt;After writing a few small things in Go, I started started the rclone project in 2012 and its been growing ever since, now with 30 thousand stars on GitHub and millions of downloads a month.&lt;/p&gt;
&lt;p&gt;That’s been quite a ride but I’ll save that story for a different talk!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-04.png&#34; alt=&#34;Slide: About rclone&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Since all the real world examples in this talk come from rclone I’ll tell you a little bit about it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://rclone.org&#34;&gt;Rclone&lt;/a&gt; is a highly concurrent command line tool to sync your data to and from any cloud storage system. It supports over 40 providers including s3, dropbox, google drive, azure and lots more.&lt;/p&gt;
&lt;p&gt;It tries to do everything it can to maximise your network and disk bandwidth and minimise the chance of data corruption.&lt;/p&gt;
&lt;p&gt;It can also mount your cloud storage system as a network drive using its FUSE filing system.&lt;/p&gt;
&lt;p&gt;To make it run fast rclone is riddled with Go routines, and the inevitable channels and locks which go with them and in turn the inevitable deadlocks.&lt;/p&gt;
&lt;p&gt;Before I started on the rclone journey I knew nothing about deadlocks!&lt;/p&gt;
&lt;h2 id=&#34;what-is-a-deadlock&#34;&gt;What is a deadlock?&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-05.png&#34; alt=&#34;Slide: What is a deadlock&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;So what is a deadlock?&lt;/p&gt;
&lt;p&gt;Here is Wikipedia’s rather abstract definition of a deadlock – something to do with one process holding something another process needs.&lt;/p&gt;
&lt;p&gt;I prefer to think of them as a catch 22 situation.&lt;/p&gt;
&lt;p&gt;Rather like a newly graduated developer: you need experience to get a job, but you can’t get experience until you get a job.&lt;/p&gt;
&lt;p&gt;In a deadlock the other process has something you want, and you have something the other process wants and you are both prepared to sit there and block forever until the other process gives you what you need.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-06.png&#34; alt=&#34;Slide: Deadlock diagram setup&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Let’s go through a deadlock in diagram form.&lt;/p&gt;
&lt;p&gt;Here we have two go routines (the blue circles labelled Process 1 and Process 2) and two locks (the pink squares).&lt;/p&gt;
&lt;p&gt;Each lock could be a sync.Mutex or a Read Write Mutex or maybe even a write to a channel.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-07.png&#34; alt=&#34;Slide: Process 1 takes Lock 1&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The first step is Process 1 takes Lock 1. All good so far.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-08.png&#34; alt=&#34;Slide: Process 2 takes Lock 2&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Next step is process 2 takes lock 2. Again all good, nothing to see here.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-09.png&#34; alt=&#34;Slide: Process 1 blocked on Lock 2&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Now process 1 attempts to takes lock 2. This causes Process 1 to block and wait for lock 2 to be released as lock 2 is already taken by process 2.&lt;/p&gt;
&lt;p&gt;We haven’t reached deadlock yet as everything could be resolved as soon as Process 2 drops Lock 2.&lt;/p&gt;
&lt;p&gt;However it doesn’t do that...&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-10.png&#34; alt=&#34;Slide: Deadlock achieved&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Process 2 now tries to take Lock 1.&lt;/p&gt;
&lt;p&gt;This is unsuccessful because Lock 1 is taken by Process 1 so Process 2 blocks waiting for it to be released.&lt;/p&gt;
&lt;p&gt;Now Process 1 &lt;strong&gt;and&lt;/strong&gt; Process 2 are blocked. They will never proceed as each is waiting for the other to release a lock.&lt;/p&gt;
&lt;p&gt;These two processes are now deadlocked.&lt;/p&gt;
&lt;p&gt;This means that some part of your program has stopped working and will &lt;strong&gt;never&lt;/strong&gt; work again.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-11.png&#34; alt=&#34;Slide: Deadlock code example&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Let’s see what that might look like in Go with a simple bit of code.&lt;/p&gt;
&lt;p&gt;We have process 1 and process 2 just like in the previous example and they are going to sit there in a loop, taking and releasing lock1 and lock2.&lt;/p&gt;
&lt;p&gt;The only difference between process1 and process2 is that they take and release the locks in a different order.&lt;/p&gt;
&lt;p&gt;This code looks like it should work, but it will deadlock pretty soon.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-12.png&#34; alt=&#34;Slide: Deadlock detector output&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This is the output once you run the code.&lt;/p&gt;
&lt;p&gt;First thing to notice is that the Go runtime has detected the deadlock giving the nice friendly message “all go routines are asleep – deadlock”.&lt;/p&gt;
&lt;p&gt;The runtime gives a backtrace of all the Go routines that are running which is very useful for working out what went wrong.&lt;/p&gt;
&lt;p&gt;The disadvantage of this is that they can be very long – even this tiny example needed 2 slides to fit it on.&lt;/p&gt;
&lt;p&gt;Go routine 1 is waiting on the select with no cases that we put in to stop the program ending too soon. We can ignore that.&lt;/p&gt;
&lt;p&gt;Goroutine 17 is in state semacquire – its deadlocked calling the sync Mutex implementation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-13.png&#34; alt=&#34;Slide: Backtrace continued&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is the next bit of the output.&lt;/p&gt;
&lt;p&gt;In goroutine 19 you can see a different bit of our code in also calling the sync Mutex implementation. Again it is deadlocked in the semacquire state.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-14.png&#34; alt=&#34;Slide: Annotated deadlock code&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;I’ve put arrows at the bits of code that the backtrace indicates the go routines are executing.&lt;/p&gt;
&lt;p&gt;You can see process1 has taken lock1 and is blocked taking lock2, whereas process 2 has taken lock2 and is blocked taking lock1.&lt;/p&gt;
&lt;p&gt;This is a clear deadlock. Whenever you see a trace where a single go routine takes more than one lock, you should be thinking about deadlocks.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-15.png&#34; alt=&#34;Slide: Deadlock diagram confirmed&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This is exactly what we expected from our initial diagram, process 1 is blocked taking lock 2 and process 2 is blocked taking lock 1.&lt;/p&gt;
&lt;p&gt;It is nice to see  theory and practice agreeing!.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-16.png&#34; alt=&#34;Slide: Go deadlock detection limits&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;You’ll have noticed that Go can detect deadlocks.&lt;/p&gt;
&lt;p&gt;This is very useful, but unfortunately it very rarely detects deadlocks in actual code.&lt;/p&gt;
&lt;p&gt;This is because &lt;strong&gt;all&lt;/strong&gt; the Go routines in your entire program have to be asleep for it to trigger and in my experience that almost never happens except in toy examples like these.&lt;/p&gt;
&lt;p&gt;There is always something else going on, like log collection or statistics calculations or something like that which means the race detector does not fire.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-17.png&#34; alt=&#34;Slide: Silent deadlock example&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This time if we add one extra go routine as indicated the deadlock detector does not kick in, and the program deadlocks silently.&lt;/p&gt;
&lt;p&gt;Or rather part of the program - process 1 and process 2 - is deadlocked but the rest of it is working fine.&lt;/p&gt;
&lt;p&gt;Unfortunately this is the usual state of affairs when debugging deadlocks – some part of your code just stops working with no other symptoms.&lt;/p&gt;
&lt;p&gt;Enough of your code may be working to give you the idea its it isn’t broken but some important part isn’t progressing.&lt;/p&gt;
&lt;p&gt;We’ll see in the next section of the talk what to do at this point.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-18.png&#34; alt=&#34;Slide: Channels and deadlocks&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;A quick diversion, as I expect this question has popped into your minds already.&lt;/p&gt;
&lt;p&gt;Can we use channels instead of those nasty Mutexes to avoid deadlocks?&lt;/p&gt;
&lt;p&gt;Alas, no, you can cause a deadlock with channels just as easily as with Mutexes and we’ll see an example of that later.&lt;/p&gt;
&lt;p&gt;In my my experience with rclone only about 10% of the deadlocks are with channels so they are less likely certainly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-19.png&#34; alt=&#34;Slide: Why deadlocks happen&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;So why do we get deadlocks?&lt;/p&gt;
&lt;p&gt;There are two ingredients.&lt;/p&gt;
&lt;p&gt;The first is concurrency. Without concurrency, that is things happening at the same time, we can’t have deadlocks.&lt;/p&gt;
&lt;p&gt;This means that single threaded code can’t have deadlocks which is a point we’ll come back to later.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-20.png&#34; alt=&#34;Slide: Locking causes deadlocks&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The next magic ingredient for deadlocks is locking.&lt;/p&gt;
&lt;p&gt;When I say Locking here I’m including channels. Reading and writing to channels can block your program just as easily as Mutexes.&lt;/p&gt;
&lt;p&gt;And if I wanted to be really precise I’d say shared resource acquisition instead of Locking because you can get deadlocks using other things other than Mutexes and channels, for example using file system locks.&lt;/p&gt;
&lt;p&gt;So where did these locks come from?&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-21.png&#34; alt=&#34;Slide: Race detector and locking&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;My excuse is the race detector made me do it :-)&lt;/p&gt;
&lt;p&gt;So what do we do to pacify the race detector? We put locking in, and sooner or later once you’ve put enough locking in you will cause a deadlock.&lt;/p&gt;
&lt;p&gt;I’m joking here of course, the go race detector is wonderful.&lt;/p&gt;
&lt;p&gt;It tells us about data races which would have caused silent corruption in our programs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-22.png&#34; alt=&#34;Slide: Race detector virtues&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Let’s just sing the virtues of the race detector for a moment. It is a technological marvel and very close to magic.&lt;/p&gt;
&lt;p&gt;The race detector will tell you when your program runs a risk of memory corruption due to unsafe accesses.&lt;/p&gt;
&lt;p&gt;If you are writing concurrent programs you should run your tests with the race detector, and if you can, some of your production binaries too.&lt;/p&gt;
&lt;p&gt;Any problems it finds are always real problems – I’ve never known it make a mistake.&lt;/p&gt;
&lt;p&gt;However when fixing the things the race detector points out, do think about what deadlocks you are about to create.&lt;/p&gt;
&lt;p&gt;In particular think about what locks might be already held and what locks you might want to take in this go routine.&lt;/p&gt;
&lt;h2 id=&#34;how-to-debug-a-deadlock&#34;&gt;How to debug a deadlock&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-23.png&#34; alt=&#34;Slide: File and Directory example&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is an example I’m going to use quite a few times.&lt;/p&gt;
&lt;p&gt;It is a simplified example from rclone’s FUSE based filing system for mounting remote cloud storage as if it were a local disk.&lt;/p&gt;
&lt;p&gt;On the left you can see the definition of the File struct. It has a name, size and a parent directory. It has a Path method which returns the full path of the File and it needs to ask its parent directory for its Path in order to do that. It has a Size method to return its size and a Truncate method showing how the size of the file might get changed.&lt;/p&gt;
&lt;p&gt;On the right we see the definition of the Directory struct. This has a name, a parent directory, a slice of files it contains and a slice of directories it contains. It has a Path method for returning its full path and it needs to find out the Path of its parent here. It also has a Size method which adds up the sizes of all the files in the directory.&lt;/p&gt;
&lt;p&gt;There is no locking in the code above, yet, but a few runs with the race detector reveals that locking is needed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-24.png&#34; alt=&#34;Slide: Adding mutex to File&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;To prevent those nasty data races we add a sync.Mutex called mu into the File structure. The name, lower case mu is traditional in Go code.&lt;/p&gt;
&lt;p&gt;Then in each of the methods we lock the mutex with mu.Lock() and defer the unlock of the mutex with the defer mu.Unlock().&lt;/p&gt;
&lt;p&gt;This means that none of the methods will ever run concurrently and it means our instance variables are safe from data race corruption – hooray!&lt;/p&gt;
&lt;p&gt;This is a standard pattern used in Go concurrent programming and hopefully you’ve seen it before.&lt;/p&gt;
&lt;p&gt;Take the lock at the start of each method and defer its release to the end – what could possibly go wrong?&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-25.png&#34; alt=&#34;Slide: Adding mutex to Directory&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;We do the same thing in the Directory structure, add a sync.Mutex called mu to the struct and then call mu.Lock() in each method and defer the mu.Unlock() until the method returns.&lt;/p&gt;
&lt;p&gt;However we’ve unwittingly caused a potential deadlock by doing this.&lt;/p&gt;
&lt;p&gt;I say potential deadlock here because when you run this code it will quite likely work just fine until just the right conditions are met.&lt;/p&gt;
&lt;p&gt;Most deadlocks are like this – they don’t stop your code the first time you create them, they come back to bite you later when you are least expecting them.&lt;/p&gt;
&lt;p&gt;Usually just after you’ve put your code into production.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-26.png&#34; alt=&#34;Slide: Provoking the deadlock&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is a bit of code to exercise the Directory and File abstractions and which will provoke the deadlock.&lt;/p&gt;
&lt;p&gt;Process1 just calls File.Path in a loop continuously. Not exactly normal usage, but we’re trying to provoke the deadlock here.&lt;/p&gt;
&lt;p&gt;Process2 just calls Directory.Size in a loop continuously.&lt;/p&gt;
&lt;p&gt;In our main function we create a root directory and put a file into it then start go routines to call process 1 and process 2.&lt;/p&gt;
&lt;p&gt;We also start a race detector defeating go routine which just sleeps for a minute.&lt;/p&gt;
&lt;p&gt;And finally the empty select statement to sleep the main go routine forever. Remember if we exit the main go routine then our program will stop, and we don’t want that.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-27.png&#34; alt=&#34;Slide: Sending SIGQUIT&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;So we run the program and it is now sitting there doing a whole heap of nothing while deadlocked.&lt;/p&gt;
&lt;p&gt;How can we find out what it is doing?&lt;/p&gt;
&lt;p&gt;If you are running on a Unix based platform (for example Linux or macOS) then you can send the process a SIGQUIT using the kill command or press Control Backslash. This will produce a nice backtrace.&lt;/p&gt;
&lt;p&gt;Windows platform users will have to work a little harder and install the HTTP debug handler from &lt;a href=&#34;https://pkg.go.dev/net/http/pprof&#34;&gt;net/http/pprof&lt;/a&gt; and I’ll show how to do that a bit later.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-28.png&#34; alt=&#34;Slide: SIGQUIT backtrace output&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This is what happened when I sent the File and Directory example program the QUIT signal.&lt;/p&gt;
&lt;p&gt;I got this nice backtrace. It’s quite long but there is a lot of stuff we can ignore.&lt;/p&gt;
&lt;p&gt;The output is divided into stanzas and at the start of each one is a little description, Here it says goroutine 0, idle.&lt;/p&gt;
&lt;p&gt;Following that is a reference to a line of source code, plus the code itself, once for each level of the call stack.&lt;/p&gt;
&lt;p&gt;In fact this is a system go routine doing something in the runtime – we can ignore it because it doesn’t have any of our code in the backtrace.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-29.png&#34; alt=&#34;Slide: Goroutine backtrace analysis&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Next we see go routine 1, select, no cases. This is the wait forever select code which we put in to stop the main function existing. We can ignore this too.&lt;/p&gt;
&lt;p&gt;Next we see go routine 5 semacquire. This one is important, semacquire means it is blocked when trying to acquire a lock. For most deadlocks you are searching for these semacquire lines first.&lt;/p&gt;
&lt;p&gt;Below the semacquire you can see a couple of lines of code in the runtime – these are in the sync.Mutex code, and finally a bit of our code in Dir.Path.&lt;/p&gt;
&lt;p&gt;We can see that Dir.Path was called by File.Path so by the time the go routine tries to acquire the Directory lock it has already acquired the File lock.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-30.png&#34; alt=&#34;Slide: Semacquire goroutine blocked&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Next we see goroutine 6 – also blocked on semacquire.&lt;/p&gt;
&lt;p&gt;It looks quite similar to the last one, two lines in sync.Mutex code and then it tring to acquire the mutex in File.Size.&lt;/p&gt;
&lt;p&gt;Looking up the backtrace you can see that File.Size was called from Dir.Size which means that this go routine acquired the Dir lock first and is now blocked on trying to acquire the File lock.&lt;/p&gt;
&lt;p&gt;If you have an editor you can click on those file names to jump to the code in question it is really helpful at this point so you can look up and down the call stack to see what other locks might be held.&lt;/p&gt;
&lt;p&gt;Under that we see go routine 7 sleep which is our deadlock defeating go routine which we can ignore.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-31.png&#34; alt=&#34;Slide: Register dump&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;And finally the register dump which you can ignore for this purpose.&lt;/p&gt;
&lt;p&gt;I’m sure the register dump is useful for low level debugging, maybe if you are writing assembler, but I’ve never needed it to debug deadlocks.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-32.png&#34; alt=&#34;Slide: Annotated deadlock backtrace&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here I’ve annotated the code from the backtrace showing where each go routine is blocked.&lt;/p&gt;
&lt;p&gt;The fact that both parts of the code are blocked on acquiring a Mutex are very suggestive that there is a deadlock.&lt;/p&gt;
&lt;p&gt;Let’s look at Dir.Path on the left hand side of the screen. We saw from examining the backtraces that this go routine already holds the file lock and is now blocked trying to acquire the directory lock.&lt;/p&gt;
&lt;p&gt;On the right File.Size is already holding the directory lock but is blocked trying to acquire the file lock.&lt;/p&gt;
&lt;p&gt;This means that these two functions are deadlocked and will block forever because the locks they are waiting for will never be released.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-33.png&#34; alt=&#34;Slide: Deadlock timeline&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This deadlock occurs whenever the Size method on Dir is called concurrently with the Path method on File.&lt;/p&gt;
&lt;p&gt;When thinking about deadlocks it is helpful to write out a timeline of the two processes involved. The numbers on the left of the code show the ordering of the calls to each process.&lt;/p&gt;
&lt;p&gt;The arrows point from the blocked locks to the place the lock is held, and them crossing is very suggestive of a deadlock.&lt;/p&gt;
&lt;p&gt;You might think that there is very little opportunity for this to happen given the short windows of opportunity – each of these instructions will be over in a few nano seconds won’t it? However, if the deadlock is possible it will happen sooner or later.&lt;/p&gt;
&lt;p&gt;One thing to bear in mind is that locking instructions are particularly slow – they use slow memory locked instructions or schedule go routines or processes - which often turns something you thought would never happen into something which always happens.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-34.png&#34; alt=&#34;Slide: HTTP debug handler&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;I’ll just quickly loop back to how to install the HTTP debug handler which you can use to collect backtraces when running Windows.&lt;/p&gt;
&lt;p&gt;Look up the docs for &lt;a href=&#34;https://pkg.go.dev/net/http/pprof&#34;&gt;net/http/pprof&lt;/a&gt; – everything you need is in there.&lt;/p&gt;
&lt;p&gt;You can collect the output with curl or just look at in your browser.&lt;/p&gt;
&lt;p&gt;You can use this on any platform of course, and you might consider leaving it in your production code for when your production code has deadlocked and you want to find out why.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-35.png&#34; alt=&#34;Slide: HTTP debug handler output&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The output from the HTTP debug handler is similar to the output from SIGQUIT with one stanza for each go routine and a trace showing position in file and the actual line of code being executed.&lt;/p&gt;
&lt;p&gt;It doesn’t call out the state of each go routine in the same way as the SIGQUIT output, but it is easy to see that the two go routines here are each blocked on SemaqcuireMutex which means blocked on acquiring a mutex as you might expect.&lt;/p&gt;
&lt;p&gt;One important difference is that this output collapses goroutines with identical stacks which can very useful if you’ve got 1000s of goroutines.&lt;/p&gt;
&lt;!-- &lt;p&gt;&lt;img src=&#34;slide-36.png&#34; alt=&#34;Slide&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;
 --&gt;
&lt;p&gt;&lt;img src=&#34;long-deadlock-log2.gif&#34; alt=&#34;Slide: Long deadlock backtrace&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;When you are tracking down a deadlock in a real world program with lots of concurrency, you’ll find that the backtraces get very long, very quickly.&lt;/p&gt;
&lt;p&gt;Deadlocks have a nasty tendency to spread through a good fraction of your running go routines until they are all waiting on a lock kind of like the way something crystallizes out of a solution.&lt;/p&gt;
&lt;p&gt;Here is an example of an backtrace a user sent me while debugging an rclone deadlock.&lt;/p&gt;
&lt;p&gt;It has nearly 2000 lines covering 260 go routines and is par for the course when dealing with lots of concurrency. There are 14 go routines blocked on acquiring a mutex, 123 blocked in a select statement, 121 blocked on sending or receving to a channel and 1 in a system call and 1 idle.&lt;/p&gt;
&lt;p&gt;If that sounds like looking for a needle in a haystack, it is, we need some help here!&lt;/p&gt;
&lt;!-- &lt;p&gt;&lt;img src=&#34;slide-37.png&#34; alt=&#34;Slide&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;
 --&gt;
&lt;p&gt;&lt;img src=&#34;panicparse_webstack.gif&#34; alt=&#34;Slide: Panicparse web output&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Luckily there is a great tool called &lt;a href=&#34;https://github.com/maruel/panicparse&#34;&gt;panic parse&lt;/a&gt; which helps enormously here.&lt;/p&gt;
&lt;p&gt;It condenses down that 2000 line log into a nicely coloured 142 line log with one stanza for each different type of go routine.&lt;/p&gt;
&lt;p&gt;It shows that there are only 14 different types of go routine here which makes working out what is going on so much easier.&lt;/p&gt;
&lt;p&gt;It also has a nice web output which I haven’t tried yet, but I’ve put up the screenshot from the github page so you can see what it is like.&lt;/p&gt;
&lt;p&gt;This tool has saved me so much time when debugging deadlocks – thank you Marc-Antoine Ruel!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-38.png&#34; alt=&#34;Slide: Panicparse text output&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The text output of panic parse shows a stanza for each go routine. It collapses go routines with similar stacks together like the HTTP debug handler, but better.&lt;/p&gt;
&lt;p&gt;Here is what a stanza looks like. On the left you can see a number – in this case 7 – this is how many go routines like this there were, and really usefully the time it has been paused. Looking for the first goroutine to pause can often be a big clue.&lt;/p&gt;
&lt;p&gt;It is then reasonably easy to see that there are only a few go routines that could possible be the problem, namely the ones that are waiting on locks that have taken locks already so we can immediately ignore nearly all the go routines.&lt;/p&gt;
&lt;p&gt;I’m not going to lie, it’s still tricky working out exactly what the cause of the deadlock from here is, but it is so much easier with panic parse.&lt;/p&gt;
&lt;h2 id=&#34;how-to-avoid-deadlocks&#34;&gt;How to avoid deadlocks&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-39.png&#34; alt=&#34;Slide: How to avoid deadlocks&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;We’ve talked so far about what a deadlock is and how to find them and debug them, but a better strategy would be to avoid them completely.&lt;/p&gt;
&lt;p&gt;I’m going to talk through a number of different techniques for avoiding deadlocks. Unfortunately there isn’t just one thing I can say – do this and you’ll never get a deadlock again, alas.&lt;/p&gt;
&lt;p&gt;We’re going to start with some easy things to fix then move on to some harder problems.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-40.png&#34; alt=&#34;Slide: Channel deadlock example&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;I said there was going to be an example of deadlocks with channels a bit later and here it is!&lt;/p&gt;
&lt;p&gt;Let’s start with a Job. You can see its struct at the top.&lt;/p&gt;
&lt;p&gt;It has a constructor NewJob which doesn’t do a lot in this example.&lt;/p&gt;
&lt;p&gt;The Process method for each job runs the Job. However in the process of running a Job, more Jobs might be created. In this example it picks a random number as to whether to create more jobs or not.&lt;/p&gt;
&lt;p&gt;Those jobs are then returned in a slice for further processing.&lt;/p&gt;
&lt;p&gt;This is simplified from an rclone example where each Job listed a directory and returned jobs to list sub directories.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-41.png&#34; alt=&#34;Slide: ProcessJobs function&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here the ProcessJobs function takes a WaitGroup and a channel of jobs. When running it takes a job out of the channel, processes it and adds any created jobs back onto the channel.&lt;/p&gt;
&lt;p&gt;It is written like this with a channel so we can run a few copies of ProcessJobs concurrently to increase the throughput and that is what happens in the main routine -
We start 3 copies of the ProcessJobs function to increase the throughput.&lt;/p&gt;
&lt;p&gt;Its worth explaining what the sync.WaitGroup does here. We are using it to keep track of the number of active jobs – whenever a job is created it is increased with the Add(1) method and whenever a job is finished it is decreased with the Done method.&lt;/p&gt;
&lt;p&gt;When the wait group goes to zero, we know all the jobs have finished and we wait for that moment with the Wait method.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-42.png&#34; alt=&#34;Slide: Channel deadlock runs&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;When we run it, it works fine for a while, running jobs, creating new ones, adding them to the channel, until...&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-43.png&#34; alt=&#34;Slide: Channel deadlock output&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;… you guessed it, we get a deadlock.&lt;/p&gt;
&lt;p&gt;The first go routine shown, go routine 1, is our sync WaitGroup waiting for the others to finish.&lt;/p&gt;
&lt;p&gt;Goroutine 6, 7 and 8 are all in state chan send. That is they are waiting for a channel to be emptied before they can send some data down it. You can see that they are all waiting in ProcessJobs.&lt;/p&gt;
&lt;p&gt;The problem is that somehow all three of our go routines are blocked writing to the channel and none of them are reading from it.&lt;/p&gt;
&lt;p&gt;Because those 3 go routines are the only place that we read from the channel, it means that the channel will never get emptied and those 3 go routines will never get unblocked, creating a deadlock.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-44.png&#34; alt=&#34;Slide: Channel deadlock annotated&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This is the code with the deadlock positions marked on it.&lt;/p&gt;
&lt;p&gt;The three ProcessJobs functions are all trying to write a new Job into the jobs channel. However none of them is reading from the channel, so none of those writes will ever succeed A classic deadlock, this time with channels.&lt;/p&gt;
&lt;p&gt;We can also see the sync.Waitgroup Wait method being called to wait for the Job processing to be complete. This is now part of the deadlock too as it will never proceed.&lt;/p&gt;
&lt;p&gt;The Waitgroup Wait isn’t the cause of the deadlock, but it is collateral damage and this is very common when looking at deadlocks. Often the collateral damage overwhelms the cause of the deadlock and that makes it very hard to work out what is going on.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-45.png&#34; alt=&#34;Slide: Channel deadlock solution&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;So what is the solution?&lt;/p&gt;
&lt;p&gt;We need the ProcessJobs function to be either reading from the channel or processing a Job. We don’t ever want it to be blocked on writing to the channel, because if one go routine can get blocked then all of them can.&lt;/p&gt;
&lt;p&gt;The easiest way of achieving this is by sending into the channel in a new go routine. The original Go routine is released to receive jobs from the channel while the new go routine sends the new jobs to the channel.&lt;/p&gt;
&lt;p&gt;This has the consequence that there might be an indefinite number of go routines with a few jobs to add to the jobs channel hanging around. If that is a problem then a different design is needed.&lt;/p&gt;
&lt;p&gt;Note we also moved the activeJobs.Done call into the new go routine – we can’t signal a job is finished until all its Job children are safely queued. If we do then the main function will end too early.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-46.png&#34; alt=&#34;Slide: Channel deadlock moral&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The moral of this channel deadlock is simple. Don’t send and receive to the same channel in the same go routine – it is a recipe for deadlocks.&lt;/p&gt;
&lt;p&gt;As I said earlier this example came straight from rclone. This dead lock took some time to appear and it took me a few iterations to a find a solution which didn’t deadlock.&lt;/p&gt;
&lt;p&gt;Concurrency is hard!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-47.png&#34; alt=&#34;Slide: RWMutex deadlock example&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is an example with read write locks.&lt;/p&gt;
&lt;p&gt;We have two main functions RO and RW. RO takes a read lock then calls MoreRO which in turn takes the Read lock again. This is allowed – read locks can be taken multiple times.&lt;/p&gt;
&lt;p&gt;The RW function takes the lock for Write.&lt;/p&gt;
&lt;p&gt;This look harmless and it works most of the time until suddenly it doesn’t and you made a deadlock as we’ll see in a moment.&lt;/p&gt;
&lt;p&gt;This example is simplified from a real world example which was caused by a bit of careless refactoring.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-48.png&#34; alt=&#34;Slide: RWMutex lock step 1&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The next step is the Read Write lock being taken in go routine 2.&lt;/p&gt;
&lt;p&gt;If you read the docs you’ll see a Read Write lock prevents any new Read locks happening so that the lock eventually becomes available.&lt;/p&gt;
&lt;p&gt;There is also a note about recursive locking not being allowed if you read carefully which is exactly what this example is about.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-49.png&#34; alt=&#34;Slide: RWMutex lock step 2&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The next step is the Read Write lock being taken in go routine 2.&lt;/p&gt;
&lt;p&gt;If you read the docs you’ll see a Read Write lock prevents any new Read locks happening so that the lock eventually becomes available.&lt;/p&gt;
&lt;p&gt;There is also a note about recursive locking not being allowed if you read carefully which is exactly what this example is about.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-50.png&#34; alt=&#34;Slide: RWMutex recursive deadlock&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The deadlock happens when go routine 1 attempts to take the read lock again. This is called recursive locking and none of the standard library locking routines support recursive locking.&lt;/p&gt;
&lt;p&gt;This lock is blocked because the Read Write lock in go routine 2 is in the process of being taken.&lt;/p&gt;
&lt;p&gt;This means that MoreRO function will never return and the RO function will never release its lock, so in its turn the RW function will never acquire the mutex.&lt;/p&gt;
&lt;p&gt;Thus, a deadlock!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-51.png&#34; alt=&#34;Slide: RWMutex deadlock moral&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;And the moral of this story is Don’t take a read lock twice in the same go routine.&lt;/p&gt;
&lt;p&gt;It might sound completely obvious but it is really easy to do by accident.&lt;/p&gt;
&lt;p&gt;It does warn explicitly against doing this in the docs too, but of course I didn’t notice that until after I caused this deadlock!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-52.png&#34; alt=&#34;Slide: Deadlock commit message&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;I could show a commit message for every one of the examples in this talk, but since we haven’t got all day I’ll just put this one up so you can feel my pain.&lt;/p&gt;
&lt;p&gt;I always find debugging deadlocks hard even with all these nice tools, so when you have to debug one yourself, just remember that!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-53.png&#34; alt=&#34;Slide: Interlinked objects deadlock&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Objects which contains locks that call each others methods are a deadlock waiting to happen.&lt;/p&gt;
&lt;p&gt;This happens naturally in more complicated systems, for example file systems, and great care needs to be taken not to cause deadlocks.&lt;/p&gt;
&lt;p&gt;Going back to our Directory and File example, the problem is caused by the fact that Directory and File both call each other’s methods.&lt;/p&gt;
&lt;p&gt;The general solution to this is called Total Lock Ordering but we’re going to look at some easier mitigations first.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-54.png&#34; alt=&#34;Slide: Shorten locking window&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is one example fix for the deadlock. I call this technique shortening the locking Window.&lt;/p&gt;
&lt;p&gt;What we’ve done here is released the mutex in the File Path method as soon as we can and in doing that the lock and unlock of the File and Directory mutexes no longer overlap.&lt;/p&gt;
&lt;p&gt;At the top you can see the original function.&lt;/p&gt;
&lt;p&gt;Below that you can see we’ve modified it to make a temporary copy of name and parent from the File then unlocked the mutex.&lt;/p&gt;
&lt;p&gt;This is enough to fix the deadlock as shown before. It does introduce the idea that the Path function might return an out of date Path if the name or parent changes during the call of Path. Some thought is required here as to whether this is OK or not.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-55.png&#34; alt=&#34;Slide: Release locks early&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;In order to minimize the chance of deadlocks, release locks as soon as possible to shorten the locking window.&lt;/p&gt;
&lt;p&gt;Specifically release them before calling any other functions or methods which might take locks.&lt;/p&gt;
&lt;p&gt;I’ve even resorted to using the defer statement to defer calls to get them outside the locking of the current method.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-56.png&#34; alt=&#34;Slide: Read-only variables&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Another easy mitigation is to notice which members of your object are read only. These should be assigned to once in the initialization of the object and never written again.&lt;/p&gt;
&lt;p&gt;These don’t need any kind of locking at all to access. Concurrent reads are always safe.&lt;/p&gt;
&lt;p&gt;So, for example, here we say that the name of files and their parent directories never change.&lt;/p&gt;
&lt;p&gt;I’ve moved them above the mutex definition to give the idea that they aren’t and don’t need to be protected by the mutex.&lt;/p&gt;
&lt;p&gt;In this rename free world, we don’t need any locking in the Path method and we fixed the deadlock by not having any locking in the File.Path method at all.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-57.png&#34; alt=&#34;Slide: No locking needed&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;If you can identify variables which are read only, you don’t need locking for them and they can be accessed outside the lock.&lt;/p&gt;
&lt;p&gt;No locking means no possibility of deadlocks.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-58.png&#34; alt=&#34;Slide: Other mitigations&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is  a sketch of some other things you can do which I didn’t have room to make examples for.&lt;/p&gt;
&lt;p&gt;Once way to reduce deadlock possibilities is to split the lock into multiple locks, so use more fine grained locking. This makes it less likely the locks will overlap.&lt;/p&gt;
&lt;p&gt;Or maybe you can use atomics for some accesses (perhaps you are incrementing a counter). Atomics never block your process so can’t cause a deadlock. They come with their own caveats so use with care.&lt;/p&gt;
&lt;p&gt;Using a Read write mutex is a great help for reducing lock contention provided you’ve got methods which only read things. Allowing many read only methods to run at once stops them blocking and minimizes the chance of deadlock.&lt;/p&gt;
&lt;p&gt;And if you are using channels, buffered channels help avoid deadlocks because they don’t synchronize two go routines. Deadlocks can still occur when the channels get full though so it wont cure everything.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-59.png&#34; alt=&#34;Slide: Total lock ordering&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Now its time to bring out the big guns.&lt;/p&gt;
&lt;p&gt;The ultimate solution to this kind of locking problem is to impose total lock ordering. This means that you are sure that if the locks overlap then you always take one lock first.&lt;/p&gt;
&lt;p&gt;So if you have two locks A and B, you always take lock A before taking lock B in the same go routine. This makes sure we never have a deadlock.&lt;/p&gt;
&lt;p&gt;This, however, is much easier said than done in a structured program with locks inside objects.&lt;/p&gt;
&lt;p&gt;In practice with object based locks and methods, this means making one object super-ordinate and one subordinate.&lt;/p&gt;
&lt;p&gt;For example this might mean that Directory can call File methods with the Directory lock held but File methods &lt;strong&gt;mustn’t&lt;/strong&gt; call Directory methods with the File lock held.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-60.png&#34; alt=&#34;Slide: Lock ordering comments&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;In a perfect world we’d be able to specify what we want to a linter. I don’t think such a linter exists yet – if it does do tell! In the mean time comments like this one from rclone are what we have to live with.&lt;/p&gt;
&lt;p&gt;It explains to the reader that the Cache and Item objects are tightly linked and that if you don’t want to cause a deadlock then don’t call Cache methods from Item with the Item lock held.&lt;/p&gt;
&lt;p&gt;This means that when you change code you need to be very careful to uphold those invariants. If you don’t, deadlocks will ensue.&lt;/p&gt;
&lt;p&gt;So make write of comments and do lots of code review when writing this sort of code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-61.png&#34; alt=&#34;Slide: Single threaded engine&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Debugging deadlocks can get very hard, very quickly and I used to think I was pretty good at this computer science stuff, but debugging deadlocks frequently makes me feel very stupid.&lt;/p&gt;
&lt;p&gt;So if the locking gets too complicated then you can bail out and use a single threaded engine to remove &lt;strong&gt;all&lt;/strong&gt; the locking.&lt;/p&gt;
&lt;p&gt;Single threaded likely means lower performance but maybe having no deadlocks is worth it.&lt;/p&gt;
&lt;p&gt;You’d communicate with the engine over channels in a request / response style. Typically you’d send the channel for the response over the request channel.&lt;/p&gt;
&lt;p&gt;This makes things much simpler and is very much in the classic Go style but making everything single threaded will drop your performance which may be unacceptable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-62.png&#34; alt=&#34;Slide: Deadlock detection tools&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;You’ll notice there’s been a lot of struggle with deadlocks in the previous slides and it would be nice if there were tools to help us find the deadlocks before they happen.&lt;/p&gt;
&lt;p&gt;Well there are a couple of notable tools for finding deadlocks in go code.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/nickng/dingo-hunter&#34;&gt;Dingo hunter&lt;/a&gt; is based of a theoretical approach for finding channel based deadlocks. You may have caught the talk about it here in 2016. It only works for unbuffered channels, alas, which limits its scope.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sasha-s/go-deadlock&#34;&gt;Go deadlock&lt;/a&gt; is a practical tool for finding violations of total lock ordering and has been used to find deadlocks in Cockroach DB for example. I’ve used it on the rclone code base a few times.&lt;/p&gt;
&lt;p&gt;It comes up with error messages that look rather like those from the race detector, but unlike the race detector it detects potential deadlocks before they happen so you can run this on your code which hasn’t deadlocked yet.&lt;/p&gt;
&lt;p&gt;Go deadlock only works for mutex deadlocks, not channel deadlocks. As I said before this is probably 90% of the deadlocks I see so it is an excellent start.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-63.png&#34; alt=&#34;Slide: Go-deadlock usage&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Go deadlock is very easy to use. Here’s the example from its GitHub page.&lt;/p&gt;
&lt;p&gt;You just replace your sync imports with a go deadlock import and when you run your code it will give total lock ordering errors.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-64.png&#34; alt=&#34;Slide: Go-deadlock output&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This is what our File and Directory example looks like when run with go deadlock.&lt;/p&gt;
&lt;p&gt;As you can see it nicely points out the potential deadlock. The top half is the first go routine and it’s saying the Directory lock then the File lock was taken but in the other go routine (the bottom half) the File lock was taken first, then the Directory lock. It isn’t saying a deadlock happened, it is just saying that because of this ordering of locks a deadlock could happen.&lt;/p&gt;
&lt;p&gt;I’ve used go-deadlock on more complicated examples and I have to say I’ve found the output quite difficult to interpret. This is because deadlocks are hard to understand rather than a shortcoming of the tool. So if you do plug go deadlock into your massive concurrent program, expect a bit of head scratching while you work out what the error messages mean!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-65.png&#34; alt=&#34;Slide: Go-deadlock script&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;When I want to use go deadlock with rclone I run this little script.&lt;/p&gt;
&lt;p&gt;It searches and replaces all the sync Mutex and sync RWMutex with their deadlock detector versions.&lt;/p&gt;
&lt;p&gt;Unfortunately I find you can’t leave Go deadlock in production code as it has too much of a performance impact.&lt;/p&gt;
&lt;p&gt;I’d like to have a neater way of enabling it for testing, but I haven’t figured that out yet.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-66.png&#34; alt=&#34;Slide: Conclusion&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This has been quite an intense talk and we’ve gone over a lot of concurrency related things, but I hope you all now have some idea of what a deadlock is, how do debug deadlocks and how to avoid them in the future.&lt;/p&gt;
&lt;p&gt;Deadlocks are the curse of concurrent programming, however there good tools for finding and debugging them and there are some promising tools for helping to prevent them happening in any code base.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-67.png&#34; alt=&#34;Slide: Do not panic&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;So if, or rather when, you get to debug your first deadlock, just remember, Don’t Panic, or rather...&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-68.png&#34; alt=&#34;Slide: Do panic for backtrace&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;...Do panic and collect a backtrace :-)&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-69.png&#34; alt=&#34;Slide: Thank you&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Thank you all very much for listening.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Xmas 2020</title>
      <link>https://www.craig-wood.com/nick/xmas/2020/</link>
      <pubDate>Fri, 25 Dec 2020 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2020/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2020]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2020 has been the best of times and the worst of times. As a family of dedicated introverts (with one exuberant exception) we’ve enjoyed spending more time at home together, meals in the garden and long walks in the local area with Pepper.&lt;/p&gt;
&lt;p&gt;The year opened with Nick finalising the sale of Memset after more than a year of intensely stressful negotiations, made harder by Nick’s sister and business partner Kate’s deteriorating mental health. Luckily Ed’s position teaching snowboarding in Austria gave the perfect excuse for a February half term holiday. Unluckily - and perhaps predictably, if you’ve been reading these messages long enough - Ed broke his arm just before we were due to visit Ellmau meaning we had to go skiing without him. Thankfully the sale of Memset completed in March. Unfortunately this was just before the first lockdown which meant Nick was unable to say a proper goodbye to everyone who worked there.&lt;/p&gt;
&lt;p&gt;Lockdown meant Issy finished Upper Sixth very suddenly, without taking her A-levels or experiencing the usual rites of passage that come with leaving school. Dougal loved spending more time at his computer but home schooling and remote Common Entrance exams turned out to be less fun than Roblox. To entertain ourselves in lockdown we incubated and hatched some eggs - we now have two fine hens and their noisy brothers have moved to the countryside.&lt;/p&gt;
&lt;p&gt;Amy, who works for Just Eat, spent the first part of the year in Bristol. In May she returned home in her new red van (which we keep mistaking for the postman!). She used her time here to build in a tiny kitchen and a very ingenious folding bed. Nick helped her with the electricals and then she set off to explore the UK with friends over the summer.&lt;/p&gt;
&lt;p&gt;Ed’s broken arm took a while to heal which made getting a job in lockdown challenging. He briefly had a job in Guildford  but since September has been working in Godalming, helping people save money by switching their broadband and electricity suppliers. With his first month’s pay he bought a new car (and the new wing mirror he needed after taking it out for the first time). Issy hopes he will have enough money to move out soon so that she can have his bedroom.&lt;/p&gt;
&lt;p&gt;Through the year Issy helped organise Quaker Senior Conference. Normally this is a residential event but Issy and the team rose to the challenge of taking it online this August. We weren’t allowed to join in, but Issy’s timetable on the door let us know what she was up to. Since September Issy has been studying Early Years Education at Guildford College.&lt;/p&gt;
&lt;p&gt;Sadly, Kate died in September of what we think was a drug overdose. This was quite a blow as she’d just come back from the Priory and we had hoped she was getting better. Having a lockdown funeral was strange with only 17 people allowed to come, but we sent her off in style with a pink glittery coffin and a motorcycle hearse.&lt;/p&gt;
&lt;p&gt;Loveday is continuing her part time MSc in between Zooming with the Quakers, knitting, gardening and looking after the family. Nick is gradually de-stressing and has been putting more energy into his open source software rclone. The 3 week Italian adventure we were looking forward to was cancelled, but we did manage holidays in Cornwall and took a wet and windy trip to Northumberland in August. Hopefully we will have some Cornwall related news to share in 2021.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Xmas 2019</title>
      <link>https://www.craig-wood.com/nick/xmas/2019/</link>
      <pubDate>Wed, 25 Dec 2019 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2019/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2019]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We were obviously very naughty in 2018 because Santa brought us norovirus for Christmas which spread through the family and laid us low for a week. Hopefully this year we’ve behaved better!&lt;/p&gt;
&lt;p&gt;Nick and Dougal had 2 ski trips this year. The first in February with Amy and cousins Olly &amp; Felix to Sauze d’Oulx, Italy. Things went well except when Amy’s blood sugar dropped too low and the time Dougal lost his snowboard down a red run… The second time was in April; this time with Ed, who, in true Ed style, managed to send his passport to the Russian embassy for a visa just before the trip, leading to a mad panic on the day of the flight and Ed missing half the holiday!&lt;/p&gt;
&lt;p&gt;In April it was our 25&lt;sup&gt;th&lt;/sup&gt; wedding anniversary.  We had a party at home and it was lovely to see so many of you there. Revisiting the wedding video provided plenty of entertainment and lots of “who’s that” moments.&lt;/p&gt;
&lt;p&gt;In July we went to the west coast of Scotland for a “summer” holiday. When the weather was good it was lovely and when it wasn’t we got very wet. We played our traditional game of cooking sausages wherever we went.  The highest scoring round was cooking on a rock in the middle of a river. We went to the Isle of Canna so Loveday could revisit her teenage years and were lucky enough to see a large pod of dolphins on the way.&lt;/p&gt;
&lt;p&gt;Amy (23) and boyfriend Jack converted an old transit van into a camper (see pic). They spent the summer travelling round Europe, returning briefly to have Amy’s braces removed (hooray!) and again to fix a bit of engine bother (“seaweed in the tank”). In August, Amy left home (sad face) and has &lt;s&gt;run away to the circus&lt;/s&gt; gone to live in Bristol, joining the graduate program for “Just Eat” in their design department where she works on the user experience (UX) of their app and website.&lt;/p&gt;
&lt;p&gt;Ed (22) left Vodafone in March to travel through Northern Europe to Moscow for 6 weeks. He then went again ending up in Scandinavia this time. After getting underfoot at home for a few weeks we packed him off on a snowboard instructor course in Austria. He passed his test (in German!) and has now just been let loose teaching in Ellmau for the season.&lt;/p&gt;
&lt;p&gt;Isabel (18) completed the job of chopping off her hair (for charity). She has enjoyed more Quaker events this year. A-levels are looming but she has decided to take a year out after them to delay having to fill in the dreaded UCAS form.&lt;/p&gt;
&lt;p&gt;Dougal (12) has spent almost every moment of his spare time playing computer games. His voice has been breaking and he has been growing, soon Amy will be the smallest in the family! School and rugby have been going well this year. Pepper won the “loveliest lady” prize in the school dog show; thank heavens she wasn’t wearing her “Foxy Lady” scent!&lt;/p&gt;
&lt;p&gt;Memset has been keeping Nick busy, celebrating 10 years being carbon neutral (you can see Nick with the award in the pic). Loveday enjoyed crochet and cookery courses and a trip to Iceland in August for her sister’s birthday where much lounging around in bathrobes was done. She then decided she was bored so signed up for a part time MSc in “Sustainability &amp; Ecology” from the &lt;a href=&#34;https://www.cat.org.uk/&#34;&gt;Centre for Alternative Technology&lt;/a&gt; in Wales. New Year’s resolution: learn to type!&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Xmas 2018</title>
      <link>https://www.craig-wood.com/nick/xmas/2018/</link>
      <pubDate>Tue, 25 Dec 2018 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2018/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2018]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Firstly apologies that the photomontage didn’t make it to press in 2017!&lt;/p&gt;
&lt;p&gt;Alas our beloved Daisy left us in November 2017.  We remained dog-less until January when we went to see Pepper, a black and tan cocker spaniel.  Pepper came to live with us in March and has been eating everything ever since.  High scores so far: 2 pairs of glasses, 1 passport and Nick’s favourite Rubik’s cube!  Fortunately she has the sweetest temperament so it is impossible to be cross with her for long.&lt;/p&gt;
&lt;p&gt;In March, Amy and the boys went to Sauze d’Oulx in Italy for skiing and pizza. In July 4 of us (+dog) had a fun week in a caravan in Scotland on the Ardnamurchan peninsula. We took inflatable kayaks with us and had great fun paddling round the beautiful scenery in between the showers and driving to distant lay-bys to get 3G signal for Issy. August saw us in Cornwall with a wet visit to Boardmasters festival. Ed competed in the Guildford skate jam unfortunately breaking something in his foot (we couldn’t have a message without a broken something from Ed!).&lt;/p&gt;
&lt;p&gt;In October we reluctantly had to say goodbye to another old friend: Treharrock Manor in Cornwall. All the Hambly family came to help with the mammoth clear out.  Fairholme now looks like an antique dealers storeroom. Nick hopes to be able to get his car back in the garage sometime next year!&lt;/p&gt;
&lt;p&gt;Amy (22) graduated with a degree in digital design from Brunel and moved back home bringing her boyfriend Jack. In October she finally had the jaw operation she has been expecting for 7 years. At last she can bite things things properly! She has been working for Dad making &lt;a href=&#34;https://www.memset.com&#34;&gt;Memset’s new website&lt;/a&gt; which she has done a splendid job of.&lt;/p&gt;
&lt;p&gt;Ed (21) has celebrated his 21st birthday, passed his driving test and completed a successful year in sales at Vodafone. He is enjoying working all day then going out every night (ah to be young!).&lt;/p&gt;
&lt;p&gt;Isabel (17) survived her GCSEs in the summer and was happy with the results.  She has now moved to a new school for the 6th form, and in an epic act of rebellion against her scientific parents is studying English, History and Religion &amp; Philosophy. She continues to enjoy young Quaker activities and has chopped off most of her hair.&lt;/p&gt;
&lt;p&gt;Dougal (11) has moved to a new school. It is a positive and encouraging environment and he is more relaxed at school than before. He has been playing football for a local club and doing a lot of computer gaming in his spare time. He has made his old man proud by learning to solve the Rubik’s cube.&lt;/p&gt;
&lt;p&gt;Nick has taken on the CEO role at Memset which has brought new challenges but he has the support of a great team. His spare time hobby has been his Open Source project &lt;a href=&#34;https://rclone.org/&#34;&gt;rclone&lt;/a&gt;.  Nick even gave &lt;a href=&#34;https://youtu.be/L1OLet9qviQ&#34;&gt;a talk about rclone&lt;/a&gt; which you can find on YouTube. Loveday’s year has been busy managing and preparing to sell Treharrock.  This has been both very sad and a great relief. She is looking forward to a slightly quieter life next year with time to read all the books from her book clubs.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Rclone and Go</title>
      <link>https://www.craig-wood.com/nick/articles/rclone-and-go-2018/</link>
      <pubDate>Wed, 21 Nov 2018 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/articles/rclone-and-go-2018/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;slide-01.png&#34; alt=&#34;Slide: Title - Rclone and Go&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This is a transcript of a talk I gave at the Go London User Group on 2018-11-21. You can &lt;a href=&#34;https://youtu.be/L1OLet9qviQ&#34;&gt;watch it on YouTube&lt;/a&gt; (26 minutes) or see the slides and read the words here.&lt;/p&gt;
&lt;p&gt;It&#39;s about &lt;a href=&#34;https://rclone.org&#34;&gt;rclone&lt;/a&gt; and how rclone uses the &lt;a href=&#34;https://golang.org&#34;&gt;Go programming language&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-02.png&#34; alt=&#34;Slide: About me&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Good evening.&lt;/p&gt;
&lt;p&gt;I’m Nick Craig-Wood and I’m here to talk about rclone. Rclone is an Open Source command line program to transfer files to and from cloud storage started by me as a hobby in 2012.&lt;/p&gt;
&lt;p&gt;First a bit about me.  I’ve loved programming ever since I was 13 with my &lt;a href=&#34;https://en.wikipedia.org/wiki/ZX80&#34;&gt;ZX80&lt;/a&gt; and have been doing it ever since.&lt;/p&gt;
&lt;p&gt;Now-a-days I’m CTO of &lt;a href=&#34;https://www.memset.com&#34;&gt;Memset Ltd&lt;/a&gt; who do cloud hosting and storage. I don’t get the chance to do a lot of coding at work any more so I now do Open Source coding as a hobby.&lt;/p&gt;
&lt;p&gt;I’ve always had a keen interest in storing data, keeping it safe and transferring it about – hence rclone which is an embodiment of those things!&lt;/p&gt;
&lt;p&gt;I used to be a data hoarder, but the house filled up with servers and disks and my wife complained about the electricity bill so I’m mostly reformed now.&lt;/p&gt;
&lt;p&gt;Thank heavens for cloud storage!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-03.png&#34; alt=&#34;Slide: Talk overview&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;My talk this evening is going to start with a quick summary of rclone and its history.&lt;/p&gt;
&lt;p&gt;I’ll dive into how it works, and show a bit of code.&lt;/p&gt;
&lt;p&gt;I’ll then discuss how you test a project like rclone and round off with a look at some of my favourite libraries.&lt;/p&gt;
&lt;p&gt;But before I get going I don’t want you to get the impression rclone is all my work. I’d like to thank my excellent core developers, the super helpful group of people on the forum and anyone who has sent a PR or raised an issue – rclone wouldn’t be what it is today without you..  Oh and thank you for everyone who has sent a PR correcting my spelling :-)&lt;/p&gt;
&lt;h2 id=&#34;what-is-rclone&#34;&gt;What is rclone?&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-04.png&#34; alt=&#34;Slide: What is rclone&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;In summary rclone is a command line program to sync your data to and from cloud providers.&lt;/p&gt;
&lt;p&gt;Rclone takes lots of care with data integrity, checking hashes at every step and preserves timestamps on your files.&lt;/p&gt;
&lt;p&gt;It can transfer data directly between cloud providers so you can use it to back up your s3 objects to google cloud storage.&lt;/p&gt;
&lt;p&gt;It has some optional features like encryption, but by and large rclone maps objects 1:1 from source to destination.&lt;/p&gt;
&lt;p&gt;There is lots more info on the website.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-05.png&#34; alt=&#34;Slide: Rclone and rsync&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Many of you will be familiar with rsync. Which is (see slide)&lt;/p&gt;
&lt;p&gt;Rclone syncing works very much like rsync.  I’ve tried to keep the flags the same where possible to make it familiar to rsync users.&lt;/p&gt;
&lt;p&gt;There is one thing rclone does not do though and that is implement the extremely clever delta encoding that rsync uses for transferring objects.&lt;/p&gt;
&lt;p&gt;That unfortunately isn’t possible when trying to copy objects 1:1 to cloud providers as they just don’t provide the API to do it.&lt;/p&gt;
&lt;p&gt;It would be possible to implement it but you’d lose that 1:1 mapping of objects.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-06.png&#34; alt=&#34;Slide: Supported providers&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Rclone supports most major cloud providers. Well I think so, they keep making new ones!&lt;/p&gt;
&lt;p&gt;Certainly all the big names are here, both for business use like s3, google cloud storage, azure blob storage and for personal like google drive and dropbox.&lt;/p&gt;
&lt;p&gt;There are also the standard protocols like FTP, SFTP, HTTP.&lt;/p&gt;
&lt;p&gt;I particularly like the HTTP backend – you point it file listing webpage (for example the ones apache generates) and it can pull the files off there recursively, or you can mount it as a disk.&lt;/p&gt;
&lt;p&gt;All rclone operations are supported by all providers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-07.png&#34; alt=&#34;Slide: Platforms and licensing&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Thanks to Go’s amazing cross compiling abilities, rclone runs on nearly every platform you can think of.&lt;/p&gt;
&lt;p&gt;Rclone is licenced under a very liberal MIT licence which means that it gets bundled into Synology NAS and other products like that.&lt;/p&gt;
&lt;p&gt;Nearly all the platforms are cross compiled on a linux host as part of the Travis build.  All except Windows and macOS which I had to build natively to fix various problems.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-08.png&#34; alt=&#34;Slide: Rclone history&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;As I began to do less programming at work, I realised I needed to do some programming at home in order to retain my sanity.&lt;/p&gt;
&lt;p&gt;In 2012 I decided to learn Go as it had just reached the exciting milestone of a 1.0 release.&lt;/p&gt;
&lt;p&gt;I made a few test programs then I wrote my first major go library, an interface for the openstack swift object storage system.&lt;/p&gt;
&lt;p&gt;I need a program to exercise that “swiftsync” which became “rclone”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-09.png&#34; alt=&#34;Slide: Why Go&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;There were some things that attracted me immediately to Go.&lt;/p&gt;
&lt;p&gt;We’d been using Python a lot at work so the single binary for a deployment was just breath of fresh air.&lt;/p&gt;
&lt;p&gt;Go excels in concurrency which is really important for rclone too.  Everything works concurrently in rclone such as  directory listings and transfers of objects.&lt;/p&gt;
&lt;p&gt;I started using Go as a new challenge and it has really brought back the joy of programming for me personally.&lt;/p&gt;
&lt;p&gt;Lastly Go is a really easy language to pick up, especially if you’ve done any programming in a language similar to C such as Java.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-10.png&#34; alt=&#34;Slide: Rclone growth stats&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;From its humble beginnings rclone has grown into quite a large project.&lt;/p&gt;
&lt;p&gt;As of today we’ve got about 11,000 stars on github, 200 contributors who’ve made 500 pull requests. Rclone get’s downloaded quarter of a million times a month and it has been packaged by the major Linux, Windows and Mac distributions.&lt;/p&gt;
&lt;p&gt;Exactly how rclone got all those users is a mystery, but being on the front page of Hacker news added about 1,000 github stars overnight.  Unfortunately at that time I was in the Outer Hebrides with no Internet so I had no idea this was happening!&lt;/p&gt;
&lt;p&gt;
  &lt;video controls style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;
    &lt;source src=&#34;../../pub/rclone/rclone-gource-visualisation-2.mp4&#34; type=&#34;video/mp4&#34;&gt;
      Sorry, your browser doesn&#39;t support embedded videos.
  &lt;/video&gt;
&lt;/p&gt;

&lt;p&gt;Here is a visualisation of rclone’s source code made with Gource.&lt;/p&gt;
&lt;p&gt;Rclone was created in 2012 and it got off to a slow start with just me – that is me whizzing about.&lt;/p&gt;
&lt;p&gt;Rclone reached v1.00 in 2014 and supported 3 backends: s3, drive and swift.&lt;/p&gt;
&lt;p&gt;Rclone gained its first external contribution in 2015.  That was when it implemented Amazon Drive and it started to get popular.&lt;/p&gt;
&lt;p&gt;In 2016 it gained some traditional protocols, SFTP and FTP and by 2017 I’d finally figured out I needed a VFS layer.  Which brings us to the frenzy of 2018!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-12.png&#34; alt=&#34;Slide: Amazon Drive incident&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;In 2017 I was surprised to find rclone in the middle of a minor media storm.&lt;/p&gt;
&lt;p&gt;This is how...In 2015 Amazon launched their Unlimited Drive Storage product.&lt;/p&gt;
&lt;p&gt;This, for a certain kind of person that you can find on the data hoarders subreddit was a personal challenge as you can imagine.&lt;/p&gt;
&lt;p&gt;The screenshot on the left was sent to me from that reddit and all the data (1 Peta byte of it) was uploaded with rclone.&lt;/p&gt;
&lt;p&gt;Rclone was banned from Amazon Cloud Drive, probably as a consequence of this, though ostensibly it was the use of encrypted keys within the binary. Amazon also shut down the unlimited Drive product in the US&lt;/p&gt;
&lt;p&gt;I was surprised to have an interview with a journalist from The Register.&lt;/p&gt;
&lt;p&gt;Rclone is still banned from Amazon Cloud Drive unless you have your own keys.&lt;/p&gt;
&lt;h2 id=&#34;how-does-it-work&#34;&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-13.png&#34; alt=&#34;Slide: How rclone works&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;I’ll now move on from the history to how it works.&lt;/p&gt;
&lt;p&gt;There are a number different functionalities of rclone. Each of these is implemented as a sub command otherwise known as a verb of the main program.&lt;/p&gt;
&lt;p&gt;You write the verbs after the command so “rclone config” or “rclone sync”.  More parameters can come after the verb.&lt;/p&gt;
&lt;p&gt;For data transfer the main 3 verbs are sync, copy and move.&lt;/p&gt;
&lt;!-- &lt;p&gt;&lt;img src=&#34;slide-14.png&#34; alt=&#34;Slide&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;
 --&gt;
&lt;p&gt;&lt;img src=&#34;rclone-config.gif&#34; alt=&#34;Slide: Rclone config demo&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The first command you run after installing rclone is “rclone config”.&lt;/p&gt;
&lt;p&gt;This starts up the old school config wizard.&lt;/p&gt;
&lt;p&gt;I think I first saw this style of config wizard in perl when configuring CPAN.&lt;/p&gt;
&lt;p&gt;It isn’t the prettiest in the world but it gets the job done!&lt;/p&gt;
&lt;p&gt;When it needs to do oauth it opens up your browser for you and redirects back to a local webserver to receive the results.&lt;/p&gt;
&lt;!-- &lt;p&gt;&lt;img src=&#34;slide-15.png&#34; alt=&#34;Slide&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;
 --&gt;
&lt;p&gt;&lt;img src=&#34;rclone-copy.gif&#34; alt=&#34;Slide: Rclone copy demo&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The next thing you are likely to want to do is copy some files.&lt;/p&gt;
&lt;p&gt;Here is a quick demo of some files being copied using “rclone copy” and “rclone ls” to list the files.&lt;/p&gt;
&lt;p&gt;Always start with “rclone copy” - don’t use “rclone sync” as that can delete files in the destination.&lt;/p&gt;
&lt;!-- &lt;p&gt;&lt;img src=&#34;slide-16.png&#34; alt=&#34;Slide&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;
 --&gt;
&lt;p&gt;&lt;img src=&#34;rclone-sync.gif&#34; alt=&#34;Slide: Rclone sync demo&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This shows the use of rclone sync.&lt;/p&gt;
&lt;p&gt;Rclone sync differs from copy in that it makes the source and destination identical.&lt;/p&gt;
&lt;p&gt;This means that it copies files to the destination and deletes any files in the destination which should be there.&lt;/p&gt;
&lt;p&gt;Always try with –dry-run first!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-17.png&#34; alt=&#34;Slide: Rclone copy diagram&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is rclone copy in diagram format.&lt;/p&gt;
&lt;p&gt;On the left are the source and destination before the command and on the right after the command.&lt;/p&gt;
&lt;p&gt;You can see that it can copy a file, ignore an unchanged file, overwrite a stale file and that it doesn’t touch files which exist in the destination already but aren’t in the source.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-18.png&#34; alt=&#34;Slide: Rclone sync diagram&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Whereas rclone sync’s job is to get the source and destination identical&lt;/p&gt;
&lt;p&gt;You can see that it can copy a file, ignore an unchanged file, overwrite a stale file and that it deletes files which exist in the destination already but aren’t in the source.&lt;/p&gt;
&lt;p&gt;Rclone sync, copy and move are all implemented by the same routine as most of the code is identical between them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-19.png&#34; alt=&#34;Slide: Rclone mount&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Rclone mount is one of my favourite features.  Mount any backend supported by rclone as a FUSE mount.&lt;/p&gt;
&lt;p&gt;This works on linux, mac and Windows.&lt;/p&gt;
&lt;p&gt;Rclone supports seeking on the files too so you can play video quite well from your cloud storage system and I know that lots of rclone users do exactly this.&lt;/p&gt;
&lt;p&gt;However if you want to open a file for both read and write or seek while writing then rclone will need to download the file and work on a cached copy.  This is part of the VFS layer in rclone which adapts rclone objects to work more like an actual file system.&lt;/p&gt;
&lt;!-- &lt;p&gt;&lt;img src=&#34;slide-20.png&#34; alt=&#34;Slide&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;
 --&gt;
&lt;p&gt;&lt;img src=&#34;rclone-ncdu.gif&#34; alt=&#34;Slide: Rclone ncdu demo&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is another of my favourite features.&lt;/p&gt;
&lt;p&gt;It is a blatant rip-off or homage as I prefer to call it of the ncdu tool. If you’ve never used it I recommend you install it right away&lt;/p&gt;
&lt;p&gt;It is the best tool for answering the question “Where is all my disk space?”.  It lets you explore your local disk using a really easy to use curses interface.&lt;/p&gt;
&lt;p&gt;I had the idea of implementing that in rclone and I needed something to do on a plane journey so hence rclone ncdu was born.&lt;/p&gt;
&lt;p&gt;It uses the excellent termbox library to implement the text based user interface.&lt;/p&gt;
&lt;h2 id=&#34;dive-into-code&#34;&gt;Dive into code&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-21.png&#34; alt=&#34;Slide: Backend Fs interface&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Now let’s dive into a bit of code.&lt;/p&gt;
&lt;p&gt;Rclone implements its backends using interfaces which won’t be a suprise. This shows the interface which all rclone backends must fulfil.&lt;/p&gt;
&lt;p&gt;Rob Pike tells us: “The bigger the interface, the weaker the abstraction” - this is a big interface :-(&lt;/p&gt;
&lt;p&gt;It is broken down into 3 sub parts in the rclone source but I’ve presented the whole interface here as it all as to be implemented for a backend.&lt;/p&gt;
&lt;p&gt;You can see the kind of methods you might expect, List, NewObject, Put and Mkdir.&lt;/p&gt;
&lt;p&gt;There are also some missing from that list which I’ll cover in a moment, like Copy.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-22.png&#34; alt=&#34;Slide: Object interface&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This is the interface a cloud storage object must fulfil.&lt;/p&gt;
&lt;p&gt;Again pretty straight forward.  Note the Hash method which you call with one of the types the Hashes method in the Fs object returns.&lt;/p&gt;
&lt;p&gt;Open reads the object and Update sets its contents.&lt;/p&gt;
&lt;p&gt;You can also read the modification time and set the modification time – something that is very important for rclone syncing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-23.png&#34; alt=&#34;Slide: Optional interfaces&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;All the backends support the interfaces in the previous two slides.  However some backends can do more, and rclone can use that.&lt;/p&gt;
&lt;p&gt;For example the Purge interface deletes a directory and everything under it.  Some backends can do that and some can’t.&lt;/p&gt;
&lt;p&gt;For example, say you were doing a server side move of an object.  Some backends can do that immediately with the Move method (for example Google Drive).  Some support Copy but not Move (for example S3).  Rclone will Copy the object then Delete it.  And some don’t support either (eg B2) in which case rclone will download the object and upload it again.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-24.png&#34; alt=&#34;Slide: Type assertions&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Here is how you might use those optional interfaces – with an type assertion.  That is straight forward go code.&lt;/p&gt;
&lt;p&gt;However, rclone backends can wrap other backends, for example the encryption backend.  The outer backend wants to expose what the inner backend can do so must implement all optional methods.  The inner backend may not implement all optional methods so we’ve got a problem.&lt;/p&gt;
&lt;p&gt;The traditional solution to this is a sentinel error which we check.  Here we call Purge and check the err value against ErrCantPurge.&lt;/p&gt;
&lt;p&gt;This works very well, provided you don’t want to know which methods are used in advance. Unfortunately rclone does need to know….&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-25.png&#34; alt=&#34;Slide: Features struct&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The solution to that is a good old fashioned struct full of function pointers.  This is filled in with a bit of reflection so doesn’t take any manual work to keep up to date.&lt;/p&gt;
&lt;p&gt;Backends which wrap other backends logical AND their own features with the features of the wrapped backend to make the final Features struct.&lt;/p&gt;
&lt;p&gt;To use Purge, say, you just check to see if the pointer is nil.  If it isn’t nil that means the method is supported so you can call it.&lt;/p&gt;
&lt;p&gt;Those of you who’ve used C++ will realise this is a re-implementation of the vtable or virtual table.  Go made the implementation straight forward though.&lt;/p&gt;
&lt;h2 id=&#34;testing&#34;&gt;Testing&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-26.png&#34; alt=&#34;Slide: Testing overview&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Lets go into how rclone is tested.&lt;/p&gt;
&lt;p&gt;As you saw earlier rclone supports lots of providers, it has lots of commands, architectures OSes. That all makes it really hard to test.&lt;/p&gt;
&lt;p&gt;Anyone think writing mocks for 27 different cloud providers would be much fun for a hobby project? No?&lt;/p&gt;
&lt;p&gt;So rclone does lots of integration tests.  These give real confidence that rclone works properly and keeps on working. After all cloud providers often change stuff.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-27.png&#34; alt=&#34;Slide: CI pipeline&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Rclone has a full continuous integration pipeline.&lt;/p&gt;
&lt;p&gt;I think we are amazingly lucky as open source programmers to be able to use Github, Travis and Appveyor for free – they are fantastic tools.&lt;/p&gt;
&lt;p&gt;The CI tests run all the non integration tests and builds binaries for all the platforms, uploading them for beta release automatically for every branch pushed to the main repository.&lt;/p&gt;
&lt;p&gt;You’ll find those at beta.rclone.org&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-28.png&#34; alt=&#34;Slide: Integration tests&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The integration tests run on a separate server.&lt;/p&gt;
&lt;p&gt;These run the tests, which are just normal go unit tests with some extra flags against all the backends.&lt;/p&gt;
&lt;p&gt;Running these tests costs money and takes a long time so I don’t run them against every pull request, only against the master branch and only once per day.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-29.png&#34; alt=&#34;Slide: Test report&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The integration tests produce a report for the developers to look at.&lt;/p&gt;
&lt;p&gt;This was a good day with only one failure out of 105 tests.&lt;/p&gt;
&lt;p&gt;Often there are lots of failures, usually because of some cloud provider glitch, but sometimes because of a change in the rclone code.&lt;/p&gt;
&lt;p&gt;Making a pretty report (well that is pretty by my standards) wasn’t high on my priority list.  However I completely messed up one of the releases by misreading the old report, so I made a report which couldn’t be misunderstood.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-30.png&#34; alt=&#34;Slide: Test framework&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;The integration tests rclone uses are standard go tests.  It is easy to add flags to the go tests and rclone adds a “-remote” flag to tell it to run the tests against an actual backend.&lt;/p&gt;
&lt;p&gt;Unlike unit tests, integration tests often fail.  The internet is a messy place – things go wrong.  The test_all framework re-runs the tests that fails to try to get them to pass.&lt;/p&gt;
&lt;p&gt;I should probably take the time to open source this framework as it could be useful elsewhere!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-31.png&#34; alt=&#34;Slide: Nested tests&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;In go1.6 the concept of nested tests was introduced.&lt;/p&gt;
&lt;p&gt;This made rclone’s life much easier.  As you can see it is only a few lines of code to run the integration test suite for a backend. Some backends run the suite more than once with different parameters.&lt;/p&gt;
&lt;p&gt;When making a new backend, you can use the integration tests as a guide for what you need to work on next and it makes the process quite enjoyable.&lt;/p&gt;
&lt;p&gt;Pre go1.6 code generation was used to make the integration tests which was rather painful so thank you to the Go team for making nested tests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-32.png&#34; alt=&#34;Slide: Test flags&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;This is something that not many people know, but can make your life much easier.&lt;/p&gt;
&lt;p&gt;You can add flags to tests. You don’t need to do anything special, just define flags with the standard library flag package.&lt;/p&gt;
&lt;p&gt;There are some great examples of this in the standard library, for instance using a “-golden” flag to make the tests files.&lt;/p&gt;
&lt;p&gt;Rclone uses flags to indicate that tests should run with a real backend, and to help debug those tests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-33.png&#34; alt=&#34;Slide: Code statistics&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Rclone is a reasonably large program now, approaching 100 thousand lines of Go code.&lt;/p&gt;
&lt;p&gt;However it is built on a fantastic set of libraries  some of which I’ll talk about in a moment.&lt;/p&gt;
&lt;p&gt;And all of that in turn is built on the go standard library.&lt;/p&gt;
&lt;p&gt;Rclone uses the vendor directory to keep that all straight, and we recently switched to “go mod” to manage that.&lt;/p&gt;
&lt;p&gt;I don’t think we can drop the vendor directory just yet as rclone needs to support old go versions for the Linux distros that package rclone. Maybe in a year or two.&lt;/p&gt;
&lt;h2 id=&#34;tools&#34;&gt;Tools&lt;/h2&gt;
&lt;!-- &lt;p&gt;&lt;img src=&#34;slide-34.png&#34; alt=&#34;Slide&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;
 --&gt;
&lt;p&gt;&lt;img src=&#34;goimports.gif&#34; alt=&#34;Slide: Goimports demo&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;I’ll just run through a few of my favourite libraries and tools that rclone uses.&lt;/p&gt;
&lt;p&gt;There are loads of other libraries I could have mentioned here so apologies to any authors I’ve missed out.&lt;/p&gt;
&lt;p&gt;My first choice is goimports.  Install it in your editor and never type an import statement again.&lt;/p&gt;
&lt;p&gt;You can see me editing a small file in emacs here and the import statements being automatically added while the code is formatted for you. It works in vim too so I’m told ;-)&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-35.png&#34; alt=&#34;Slide: Cobra library&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Cobra is excellent for organising command line programs with lots of verbs.&lt;/p&gt;
&lt;p&gt;I’m sure many of you have used kubectl to control kubernetes or used docker – that is cobra in action.&lt;/p&gt;
&lt;p&gt;Cobra comes with a flag library pflag which allows you to create POSIX flags.  Flags made by the go flag library are somewhat old school in comparison.&lt;/p&gt;
&lt;p&gt;Cobra also creates your bash completion script for all those people like me who use bash, but hate writing bash scripts!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-36.png&#34; alt=&#34;Slide: Cobra documentation&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Cobra helps with the documentation.  When you write a command cobra makes command help for it and then has a really easy way of turning that into markdown for the website.&lt;/p&gt;
&lt;p&gt;A lot of the help on the rclone website was generated this way and it really helps keeping everything consistent.&lt;/p&gt;
&lt;p&gt;I then use pandoc to turn the markdown into a man page and one big HTML document for the download.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-37.png&#34; alt=&#34;Slide: Error handling&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;If you’ve been keeping up with go news you’ll have read the errors proposal for go 2.&lt;/p&gt;
&lt;p&gt;The pkg/errors package was one of the motivations for the proposal, so I imagine at some time I’ll be retiring it when go 2 comes along.&lt;/p&gt;
&lt;p&gt;You use it to annotate your errors as they bubble up through your code.&lt;/p&gt;
&lt;p&gt;This means that rather than receiving a log message with “unexpected EOF” you receive a helpful message which gives you some idea as to what really went wrong.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;slide-38.png&#34; alt=&#34;Slide: Open source tips&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;I’m just going to talk briefly about what to do if your open source package takes off.&lt;/p&gt;
&lt;p&gt;It is easy to get daunted by 100s of issues most of which are support requests so the first thing to do is open a forum and get the users helping themselves.  I use Discourse – it is free and easy to setup and maintain.&lt;/p&gt;
&lt;p&gt;Don’t be shy of asking users who make issues for help.  You might need to give them a bit of a helping hand, but that is a positive process for both parties.&lt;/p&gt;
&lt;p&gt;When you’ve had a few good pull requests from someone, recruit them!&lt;/p&gt;
&lt;p&gt;Oh yes, write lots of docs – maybe that should have gone first.&lt;/p&gt;
&lt;p&gt;Finally get octobox.io – rather than managing 100s of emails from Github manage them in a nice web interface where you can filter etc.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;slide-39.png&#34; alt=&#34;Slide: Thank you&#34; style=&#34;width: 80%; height: auto; border: 5px solid #555; border-radius: 15px;&#34;&gt;&lt;/p&gt;

&lt;p&gt;Thank you all for listening :-)&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Xmas 2016</title>
      <link>https://www.craig-wood.com/nick/xmas/2016/</link>
      <pubDate>Sun, 25 Dec 2016 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2016/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2016]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In March all 6 of us piled in the trusty people carrier and drove to a friend’s &lt;a href=&#34;http://www.skiadventures.co.uk/&#34;&gt;self catering ski chalet in Les Arcs&lt;/a&gt;. We had fun skiing and finding the many uses of WiFi on holiday. Nick and Dougal went skiing together every day logging their top speeds on the resort app. Amy found 3 friends in the resort. Ed slept a lot, snowboarded a bit and broke nothing! Issy did a small amount of skiing but mostly watched Netflix.  Loveday learned to crochet thanks to YouTube (see if you can find it in the picture).&lt;/p&gt;
&lt;p&gt;The summer saw Nick taking July off work which we mostly spent in Cornwall on a DIY marathon. At the end of August we did our next great drive.  We started out by going to Reading Festival to see “twenty one pilots” leaving there late to drive to Stafford, slept for 4 hours then carried on up to Ullapool to catch the ferry to Stornaway on Lewis and thence to Valtos.  The next day was glorious and the two scenes at the top of the picture are from that day.  The weather went downhill, but we enjoyed: seeing standing stones; lots of kite flying; a happy day tie dying in the garden; a boat trip and seeing seals, black houses and iron age dwellings.  This holiday we enjoyed not having WiFi or phone signal unless standing in the sea where you can see the unprecedented sight of Issy talking to her friend on her phone.&lt;/p&gt;
&lt;p&gt;Amy (20) is in her 3rd year at uni doing a year in industry.  She managed to land herself a great job just before the deadline as a front-end developer for &lt;a href=&#34;https://www.dusted.com/&#34;&gt;Dusted, a digital agency in London&lt;/a&gt;. She enjoys photography and reluctantly lives at home.&lt;/p&gt;
&lt;p&gt;Ed (19) now has two jobs, one at the café at the sports centre, the other at Topman. He is still trying to work out what he is doing next but his parents are pleased he is gainfully employed.&lt;/p&gt;
&lt;p&gt;Isabel (15) has had an unusually active year, getting a surf board for her birthday (“Doris”), and doing her Duke of Edinburgh award which involved actually walking for really quite a long time. She is trying to watch every TV show in existence in her spare time and has almost succeeded.  She has also done some homework.&lt;/p&gt;
&lt;p&gt;Dougal (9) along with learning to ski, has also learnt to unicycle (wobbling in father’s wheel track).  He has been enjoying football, rugby and cricket at school. In Cornwall he has really got into surfing, taking over Ed’s old board (see picture).&lt;/p&gt;
&lt;p&gt;Nick has been changing role at work trying to do less management and more technical strategy which has been a welcome transformation. He has also continued art classes and writing open source software (eg &lt;a href=&#34;http://rclone.org&#34;&gt;rclone&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Loveday has been busy.  The management of &lt;a href=&#34;http://www.treharrock.com/&#34;&gt;Treharrock&lt;/a&gt; has required lots of trips to Cornwall and many hours sorting out the waste contract.  She has started an upholstery course which is a very expensive way of getting second hand furniture!  She has also finished knitting a jumper for Issy and even better it still just about fits.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Snake Puzzle Solver</title>
      <link>https://www.craig-wood.com/nick/articles/snake-puzzle/</link>
      <pubDate>Sun, 25 Sep 2016 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/articles/snake-puzzle/</guid>
      <description>&lt;p&gt;My family know I like puzzles so they gave me this one recently:&lt;/p&gt;
&lt;div class=&#34;card float-right&#34; style=&#34;max-width: 18rem;&#34;&gt;
  &lt;div class=&#34;card-header&#34; style=&#34;padding: 5px 10px;&#34;&gt;
    Fork me on Github
  &lt;/div&gt;
  &lt;div class=&#34;card-body&#34;&gt;
    The code for this along with a Jupyter notebook for it is &lt;a href=&#34;https://github.com/ncw/snake-puzzle/&#34;&gt;on
github&lt;/a&gt;.
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src=&#34;snake-puzzle-boxed.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;When you take it out the box it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;snake-puzzle-solved.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;And very soon after it looked like this (which explains why I&#39;ve
christened the puzzle &amp;quot;the snake puzzle&amp;quot;):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;snake-puzzle-flat.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The way it works is that there is a piece of elastic running through
each block. On the majority of the blocks the elastic runs straight
through, but on some of the it goes through a 90 degree bend. The puzzle
is trying to make it back into a cube.&lt;/p&gt;
&lt;p&gt;After playing with it a while, I realised that it really is quite hard
so I decided to write a program to solve it.&lt;/p&gt;
&lt;p&gt;The first thing to do is find a representation for the puzzle. Here is
the one I chose:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# definition - number of straight bits, before 90 degree bend&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;snake &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;assert&lt;/span&gt; sum(snake) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you look at the picture of it above where it is flattened you can see
where the numbers came from. Start from the right hand side.&lt;/p&gt;
&lt;p&gt;That also gives us a way of calculating how many combinations there are.
At each 90 degree joint, there are 4 possible rotations (ignoring the
rotations of the 180 degree blocks) so there are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt;len(snake)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;17179869184&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;17 billion combinations. That will include some rotations and
reflections, but either way it is a big number.&lt;/p&gt;
&lt;p&gt;However it is very easy to know when you&#39;ve gone wrong with this kind
of puzzle - as soon as you place a piece outside of the boundary of the
3x3x3 block you know it is wrong and should try something different.&lt;/p&gt;
&lt;p&gt;So how to represent the solution? The way I&#39;ve chosen is to represent
it as a 5x5x5 cube. This is larger than it needs to be but if we fill in
the edges then we don&#39;t need to do any complicated comparisons to see
if a piece is out of bounds. This is a simple trick but it saves a lot
of code.&lt;/p&gt;
&lt;p&gt;I&#39;ve also chosen to represent the 3d structure not as a 3d array but as
a 1D array (or &lt;code&gt;list&lt;/code&gt; in python speak) of length 5 x 5 x 5 = 125.&lt;/p&gt;
&lt;p&gt;To move in the &lt;code&gt;x&lt;/code&gt; direction you add 1, to move in the &lt;code&gt;y&lt;/code&gt; direction you
add 5 and to move in the &lt;code&gt;z&lt;/code&gt; direction you move 25. This simplifies the
logic of the solver considerably - we don&#39;t need to deal with vectors.&lt;/p&gt;
&lt;p&gt;The basic definitions of the cube look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;N &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xstride&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# number of pieces to move in the x direction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ystride&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;N    &lt;span style=&#34;color:#75715e&#34;&gt;# number of pieces to move in the y direction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zstride&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;N&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;N  &lt;span style=&#34;color:#75715e&#34;&gt;# number of pieces to move in the z direction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In our &lt;code&gt;list&lt;/code&gt; we will represent empty space with &lt;code&gt;0&lt;/code&gt; and space which
can&#39;t be used with &lt;code&gt;-1&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;empty &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now define the empty cube with the boundary round the edges:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Define cube as 5 x 5 x 5 with filled in edges but empty middle for&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# easy edge detection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;top &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;N&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;N
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;middle &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; [&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; [&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cube &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; top &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; middle&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; top
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&#39;re going to want a function to turn &lt;code&gt;x, y, z&lt;/code&gt; co-ordinates into an
index in the &lt;code&gt;cube&lt;/code&gt; list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pos&lt;/span&gt;(x, y, z):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Convert x,y,z into position in cube list&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;y&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;ystride&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;z&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;zstride
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So let&#39;s see what that cube looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;print_cube&lt;/span&gt;(cube, margin&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Print the cube&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; z &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(margin,N&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;margin):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; y &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(margin,N&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;margin):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(margin,N&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;margin):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cube[pos(x,y,z)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    s &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; . &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    s &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%02d&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                print(s, sep&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, end&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            print()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; print_cube(cube, margin &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Normally we&#39;ll print it without the margin.&lt;/p&gt;
&lt;p&gt;Now let&#39;s work out how to place a segment.&lt;/p&gt;
&lt;p&gt;Assuming that the last piece was placed at &lt;code&gt;position&lt;/code&gt; we want to place a
segment of &lt;code&gt;length&lt;/code&gt; in &lt;code&gt;direction&lt;/code&gt;. Note the &lt;code&gt;assert&lt;/code&gt; to check we
aren&#39;t placing stuff on top of previous things, or out of the edges:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;place&lt;/span&gt;(cube, position, direction, length, piece_number):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Place a segment in the cube&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(length):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        position &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; direction
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;assert&lt;/span&gt; cube[position] &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; empty
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cube[position] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; piece_number
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        piece_number &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; position
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&#39;s just try placing some segments and see what happens:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; cube2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cube[:] &lt;span style=&#34;color:#75715e&#34;&gt;# copy the cube&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; place(cube2, pos(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), xstride, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; print_cube(cube2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;02&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;03&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; place(cube2, pos(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), ystride, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; print_cube(cube2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;02&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;03&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;04&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;05&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; place(cube2, pos(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), zstride, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; print_cube(cube2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;02&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;03&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;04&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;05&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;06&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;07&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next thing we&#39;ll need is to undo a place. You&#39;ll see why in a
moment.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unplace&lt;/span&gt;(cube, position, direction, length):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Remove a segment from the cube&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(length):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        position &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; direction
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cube[position] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; empty
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; unplace(cube2, pos(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), zstride, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; print_cube(cube2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;02&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;03&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;04&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;05&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now let&#39;s write a function which returns whether a move is valid given
a current &lt;code&gt;position&lt;/code&gt; and a &lt;code&gt;direction&lt;/code&gt; and a &lt;code&gt;length&lt;/code&gt; of the segment we
are trying to place.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is_valid&lt;/span&gt;(cube, position, direction, length):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Returns True if a move is valid&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(length):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        position &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; direction
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; cube[position] &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; empty:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; is_valid(cube2, pos(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), zstride, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; is_valid(cube2, pos(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), zstride, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given &lt;code&gt;is_valid&lt;/code&gt; it is now straight forward to work out what moves are
possible at a given time, given a &lt;code&gt;cube&lt;/code&gt; with a &lt;code&gt;position&lt;/code&gt;, a
&lt;code&gt;direction&lt;/code&gt; and a &lt;code&gt;length&lt;/code&gt; we are trying to place.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# directions next piece could go in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;directions &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [xstride, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;xstride, ystride, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;ystride, zstride, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;zstride]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;moves&lt;/span&gt;(cube, position, direction, length):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Returns the valid moves for the current position&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    valid_moves &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; new_direction &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; directions:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Can&amp;#39;t carry on in same direction, or the reverse of the same direction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; new_direction &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; direction &lt;span style=&#34;color:#f92672&#34;&gt;or&lt;/span&gt; new_direction &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;direction:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; is_valid(cube, position, new_direction, length):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            valid_moves&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append(new_direction)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; valid_moves
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; moves(cube2, pos(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), ystride, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So that is telling us that you can insert a segment of length 2 using a
direction of &lt;code&gt;-xstride&lt;/code&gt; or &lt;code&gt;zstride&lt;/code&gt;. If you look at previous
&lt;code&gt;print_cube()&lt;/code&gt; output you&#39;ll see those are the only possible moves.&lt;/p&gt;
&lt;p&gt;Now we have all the bits to build a recursive solver.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;solve&lt;/span&gt;(cube, position, direction, snake, piece_number):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Recursive cube solver&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; len(snake) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Solution&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print_cube(cube)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    length, snake &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; snake[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], snake[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    valid_moves &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; moves(cube, position, direction, length)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; new_direction &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; valid_moves:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        new_position &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; place(cube, position, new_direction, length, piece_number)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        solve(cube, new_position, new_direction, snake, piece_number&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;length)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        unplace(cube, position, new_direction, length)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works by being passed in the &lt;code&gt;snake&lt;/code&gt; of moves left. If there are no
moves left then it must be solved, so we print the solution. Otherwise
it takes the head off the &lt;code&gt;snake&lt;/code&gt; with
&lt;code&gt;length, snake = snake[0], snake[1:]&lt;/code&gt; and makes the list of valid moves
of that &lt;code&gt;length&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then we &lt;code&gt;place&lt;/code&gt; each move, and try to &lt;code&gt;solve&lt;/code&gt; that cube using a
recursive call to &lt;code&gt;solve&lt;/code&gt;. We &lt;code&gt;unplace&lt;/code&gt; the move so we can try again.&lt;/p&gt;
&lt;p&gt;This very quickly runs through all the possible solutions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Start just off the side&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;position &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pos(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;direction &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; xstride
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;length &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; snake[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Place the first segment along one edge - that is the only possible place it can go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;position &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; place(cube, position, direction, length, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Now solve!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;solve(cube, position, direction, snake[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:], length&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-py3&#34; data-lang=&#34;py3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Solution
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;02&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;03&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;04&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;07&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;06&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;05&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;08&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;18&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;26&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;09&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Solution
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;02&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;03&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;04&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;18&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;26&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;07&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;06&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;05&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;08&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;09&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wow! It came up with 2 solutions! However they are the same solution
just rotated and reflected.&lt;/p&gt;
&lt;p&gt;But how do you use the solution? Starting from the correct end of the
snake, place each piece into its corresponding number. Take the first
layer of the solution as being the bottom (or top - whatever is
easiest), the next layer is the middle and the one after the top.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;snake-puzzle-flat-numbered.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;After a bit of fiddling around you&#39;ll get...&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;snake-puzzle-solved.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;I hope you enjoyed that introduction to puzzle solving with computer.&lt;/p&gt;
&lt;p&gt;If you want to try one yourselves, use the same technique to solve
solitaire.&lt;/p&gt;
&lt;p&gt;Download the entire code
&lt;a href=&#34;snake_puzzle_solver.py&#34;&gt;snake_puzzle_solver.py&lt;/a&gt; or the &lt;a href=&#34;snake_puzzle_solver.ipynb&#34;&gt;iPython
notebook&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Xmas 2015</title>
      <link>https://www.craig-wood.com/nick/xmas/2015/</link>
      <pubDate>Fri, 25 Dec 2015 00:00:00 +0000</pubDate>
      <author>nick@craig-wood.com (Nick Craig-Wood)</author>
      <guid>https://www.craig-wood.com/nick/xmas/2015/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;large.jpg&#34;&gt;&lt;img src=&#34;small.jpg&#34; alt=&#34;[Xmas 2015]&#34; class=&#34;center&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We brought in this year by spending Christmas and New Year at Polzeath beach in Cornwall where we had a lovely time with family and friends.  It was our last Christmas with Loveday&#39;s mother Elizabeth who died of pancreatic cancer in February after a 4 month illness.  She was cared for at home by her children until the end which was an intense but rewarding experience.&lt;/p&gt;
&lt;p&gt;After that we needed a holiday so all 6 of us spent Easter in Barcelona where we had good weather and Nick got to see the Dali museum which has been a lifelong ambition.  Not all the children were terribly impressed by the culture! Soon after we started rebuilding our garage, attaching it to the house with extra rooms above, so imagine the rest of the year to the background of builders.  The builders have done a great job and finished just in time for Christmas.&lt;/p&gt;
&lt;p&gt;In July 5 of us spent 2 weeks in Turkey near Marmaris mostly relaxing with a bit of watersport and a few visits to local highlights such as the mud baths.  Dougal learnt to sail, windsurf and waterskii all in two weeks which was amazing.  Later in the summer we had a really enjoyable week at Treharrock with university friends and their families.&lt;/p&gt;
&lt;p&gt;Amy (19) is in her second year at Brunel University.  She is enjoying leaving projects to the last minute and, having swapped 4 legs for 4 wheels, driving between home, uni and boyfriend.  Her passion for horses is being kept alive at university where she is captain of the riding team.  This seems to mostly involve lots of meetings and sorting out arguments.  She is currently working at PC World selling cameras and declining unwanted offers of marriage.&lt;/p&gt;
&lt;p&gt;Ed (18) and school had a mutually agreeable parting of the ways after his AS results and he is now studying at the university of life.  He spend a few weeks as a builder on our building site and gave the garage a thorough christening by inviting 100 people for his 18th party.  He is now working full time at Côte restaurant as a commis waiter where he enjoys visits from his family.  He still loves skateboarding despite having broken his collarbone while going off piste down a grassy bank in the spring.&lt;/p&gt;
&lt;p&gt;Isabel (14) became the second member of the family to help organise a Quaker event (YPP).  She loves these events and has been to several this year.  She continues her iPad addiction and hasn’t stopped complaining about the consequent WiFi curfew! She enjoyed bringing her friends to Cornwall and has been making good progress at school.&lt;/p&gt;
&lt;p&gt;Dougal (8) is really getting stuck in at his new school proving himself a determined football and rugby player.  At home his new hobby is weaponising stationery and using Isabel for target practice.&lt;/p&gt;
&lt;p&gt;Loveday and Nick have both been extremely busy in 2015.  Nick has being doing more management at Memset but has preserved his sanity with art classes and a writing open source software.  Loveday has overseen the building work, had many trips to Cornwall and excitingly taken on the management of Treharrock with a bit of Yoga to de-stress.&lt;/p&gt;
</description>
    </item>
  </channel>
</rss>
