<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Steven Gravell – mokele.co.uk</title>
 <link href="http://mokele.co.uk/atom.xml" rel="self"/>
 <link href="http://mokele.co.uk/"/>
 <updated>2018-06-24T18:10:27+01:00</updated>
 <id>http://mokele.co.uk/</id>
 <author>
   <name>Steven Gravell</name>
   <email>steve@mokele.co.uk</email>
 </author>

 
 <entry>
   <title>More Learning... and More Beer!</title>
   <link href="http://mokele.co.uk/2013/06/09/more-learning-and-more-beer.html"/>
   <updated>2013-06-09T00:00:00+01:00</updated>
   <id>http://mokele.co.uk/2013/06/09/more-learning-and-more-beer</id>
   <content type="html">&lt;style type=&quot;text/css&quot;&gt;
#post img {
  width: 450px;
  margin: 0 auto;
}
#post img, iframe.vine-embed {
  border: 1px solid #333;
  display: block;
}
iframe.vine-embed {
  margin-left: auto;
  margin-right: auto;
}
.brief {
  margin: 1em 0;
}
&lt;/style&gt;

&lt;div class=&quot;brief&quot;&gt;
&lt;p&gt;Here I am, a few weeks into homebrewing, and I've already brewed 3
times – and hoping to fit them in a lot more often
post-thirtieth birthday shenanegans. The first beer I made 
&lt;a href=&quot;/2013/05/24/gyle-0.html&quot;&gt;Gyle Zero&lt;/a&gt; was an amber style
citrusy hoppy beer with a lot of crystal malt flavour (which I totally winged),
my second which I am now drinking the first bottle of is a hoppy pale
ale, and the third once it's finished fermenting will be a 2.something%
simple dark mild. I have some simple things to say regarding homebrewing
for this short amount of time:
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;just start brewing&lt;/strong&gt; / wing it&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;get to know your kit through brewing with it&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;it you don't hit the gravity you want, it doesn't matter. You can
either, do nothing about it or if you have the option add more water
before pitching yeast. It'll be fine.&lt;/li&gt;
  &lt;li&gt;get to know hops through using them, it's more than likely it
will not be undrinkinable&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;heres-a-list-of-things-i-changed-after-gyle-zero&quot;&gt;&lt;span&gt;Here’s a list of things I changed after Gyle Zero&lt;/span&gt;&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Use the Raspberry-Pi to do temperature regulation in both
  kettles&lt;/li&gt;
  &lt;li&gt;Less Mash liqour and more Sparge liqour&lt;/li&gt;
  &lt;li&gt;After Run-Off and Sparge clean out Mash and distribute Wort evenly
  between both the original Mash Kettle and my second Kettle to do 2
  Boils rather than one to prevent dangerous bubbling over. All
  additions are evenly distributed among both Kettles.&lt;/li&gt;
  &lt;li&gt;For the second brew I adopted a HERMS (Heat-Exchange Recirculated
  Mash System) to regulate and even raise mash temperature. You can
  see evidence of this in the graph below.&lt;/li&gt;
  &lt;li&gt;For the third brew I recirculated after the Boil through the
  heat-exchanger to lower the temperature faster. This cut down
  transfer time to Fermentor by around half. You can see evidence of
  this in the graphs below.&lt;/li&gt;
  &lt;li&gt;Liqour back after boil to hit desired gravity.&lt;/li&gt;
  &lt;li&gt;Use the pumps I have and lines to put a bottle on the end of a tube
  to more effectively pressure clean the bottle with alkaline based 
  detergent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s some pics and graphs and recipes:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BMUHtpdCIAAiniY.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BMUHtpdCIAAiniY.jpg&quot; alt=&quot;Bottled for only 2 days&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;gyle-one&quot;&gt;&lt;span&gt;Gyle One&lt;/span&gt;&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;12L Mash&lt;/li&gt;
  &lt;li&gt;26L Sparge&lt;/li&gt;
  &lt;li&gt;5kg Maris Otter Pale&lt;/li&gt;
  &lt;li&gt;500g Cara&lt;/li&gt;
  &lt;li&gt;500g Wheat&lt;/li&gt;
  &lt;li&gt;33g Galaxy 14.4α @ 90m&lt;/li&gt;
  &lt;li&gt;20g Challenger 7.12α @ 90m&lt;/li&gt;
  &lt;li&gt;25g Galaxy 14.4%α @ 20m&lt;/li&gt;
  &lt;li&gt;25g Simcoe 11.9%%α @ 20m&lt;/li&gt;
  &lt;li&gt;25g Galaxy 14.4%α @ 5m&lt;/li&gt;
  &lt;li&gt;25g Simcoe 11.9%%α @ 5m&lt;/li&gt;
  &lt;li&gt;Liqour Back to hit 1.048 post-boil&lt;/li&gt;
  &lt;li&gt;Safale US-05 Yeast&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.google.com/spreadsheet/pub?key=0Amz8p9f9sUNZdExWVTdINVpHQzBoODllRENSd3Qybnc&amp;amp;gid=1&amp;amp;output=html&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BLtjK8FCIAENjXj.png&quot; alt=&quot;Temperature Profile&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;gyle-two&quot;&gt;&lt;span&gt;Gyle Two&lt;/span&gt;&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;12L Mash&lt;/li&gt;
  &lt;li&gt;28L Sparge&lt;/li&gt;
  &lt;li&gt;2.5kg Maris Otter Pale&lt;/li&gt;
  &lt;li&gt;250g Wheat&lt;/li&gt;
  &lt;li&gt;250g Munich&lt;/li&gt;
  &lt;li&gt;250g Crystal&lt;/li&gt;
  &lt;li&gt;150g Chocolate Malt&lt;/li&gt;
  &lt;li&gt;100g Toasted Chocolate Malt (I toasted in my dry frying pan)&lt;/li&gt;
  &lt;li&gt;30g Fuggles 4.35α @ 90m&lt;/li&gt;
  &lt;li&gt;10g Fuggles 4.35α @ 5m&lt;/li&gt;
  &lt;li&gt;10g Willamette 6.3%α @ 5m&lt;/li&gt;
  &lt;li&gt;Accidently rinse your lines too much that ends up in the beer
leading to just 1.030 post-boil&lt;/li&gt;
  &lt;li&gt;Safale S-04 Yeast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.google.com/spreadsheet/pub?key=0Amz8p9f9sUNZdEExSkw2NzdrUW9BZGp0eXlMemZpbUE&amp;amp;gid=1&amp;amp;output=html&quot;&gt;&lt;img src=&quot;http://new.tinygrab.com/ff219525e35d14b1e630c507045f92d82f727de5b9.png&quot; alt=&quot;Temperature Profile&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>What I've Learnt From My First All-Grain Homebrew</title>
   <link href="http://mokele.co.uk/2013/05/28/what-i-have-learnt-from-my-first-all-grain-homebrew.html"/>
   <updated>2013-05-28T00:00:00+01:00</updated>
   <id>http://mokele.co.uk/2013/05/28/what-i-have-learnt-from-my-first-all-grain-homebrew</id>
   <content type="html">&lt;style type=&quot;text/css&quot;&gt;
#post img {
  width: 450px;
  margin: 0 auto;
}
#post img, iframe.vine-embed {
  border: 1px solid #333;
  display: block;
}
iframe.vine-embed {
  margin-left: auto;
  margin-right: auto;
}
.brief {
  margin: 1em 0;
}
&lt;/style&gt;

&lt;div class=&quot;brief&quot;&gt;
&lt;p&gt;My last post about &lt;a href=&quot;/2013/05/24/gyle-0.html&quot;&gt;Gyle Zero&lt;/a&gt; 
was basically a &quot;werhoo! it sortof
worked!&quot; post, along with a fun graph of the temperatures and major
events during the mash, boil, and transfer. Now I'm going to go through
all the various parts of the process that I either cocked-up entirely,
or semi-cocked-up, like having the mash be too wet, and doing a one-pass
counterflow heat exchange, which took AGES. I better also write out the
recipe! It's down to 1.025 from 1.060 OG now and it's tasting great :)&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;3kg Pale&lt;/li&gt;
  &lt;li&gt;1kg Munich&lt;/li&gt;
  &lt;li&gt;1kg Crystal&lt;/li&gt;
  &lt;li&gt;500g Wheat&lt;/li&gt;
  &lt;li&gt;30g Chinook 13.3%α @ 90m&lt;/li&gt;
  &lt;li&gt;20g Cascade 7.5%α @ 15m&lt;/li&gt;
  &lt;li&gt;20g Citra 14.4%%α @ 15m&lt;/li&gt;
  &lt;li&gt;20g Cascade 7.5%α @ 0m&lt;/li&gt;
  &lt;li&gt;20g Citra 14.4%%α @ 0m&lt;/li&gt;
  &lt;li&gt;Safale S-04&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was planning on hopping the secondary over night while I make sure the
krausening is definitely working before bottling the following day,
but it tastes rather good right now, so am happy to leave the recipe the way it is.&lt;/p&gt;

&lt;p&gt;Here's a list of things I've learnt with some images:&lt;/p&gt;
&lt;/div&gt;

&lt;iframe class=&quot;vine-embed&quot; src=&quot;https://vine.co/v/bVpLtJWMAha/embed/postcard&quot; width=&quot;480&quot; height=&quot;540&quot; frameborder=&quot;0&quot;&gt;-&lt;/iframe&gt;
&lt;script async=&quot;yes&quot; src=&quot;//platform.vine.co/static/scripts/embed.js&quot; charset=&quot;utf-8&quot;&gt;/**/&lt;/script&gt;

&lt;h2 id=&quot;if-your-mash-is-too-wet-adding-the-grist-wont-make-much-or-any-difference-to-the-current-temperature&quot;&gt;&lt;span&gt;If your mash is too wet, adding the grist won’t make much or any difference to the current temperature&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;I had planned for the Mash to be around 63C so hit around 71 strike
temperature assuming the grist would lower this, it did not. It stayed
stable, only coming down quickly when I stirred and removed the lid. Rob
the head brewer at work later mentioned I could have recirculated via
the heat exchanger to cool this down a lot faster, but I think I was too
scared of too many variables of me messing about, so instead left it to
lower down to 63 over 90 minutes. &lt;em&gt;Next time I’ll use less mash
liquor, more sparge liqour, and a closer strike temperature to what I
want for my first mash rest.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BLCUbyrCcAIQKW7.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BLCUbyrCcAIQKW7.jpg&quot; alt=&quot;Wort Run-off&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;boiling-25-30l-of-wort-is-dangerous&quot;&gt;&lt;span&gt;Boiling 25-30L of wort is dangerous&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;With the kettle lid on the rolling boil would get a bit too violent and
splurt out the sides, this meant I had to have the lid partially on
leading to a large amount of loss to evaporation. &lt;em&gt;Next time I am going
to do 5L less volume, liqour back during/after transfer to FV, and also
attempt to put the lid back on after the initial violent boil stage.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BLCUpB3CIAEkYyt.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BLCUpB3CIAEkYyt.jpg&quot; alt=&quot;Boil&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;there-is-plenty-of-hopped-wort-left-over-in-the-bottom-of-the-boiler-to-set-aside-for-krausening&quot;&gt;&lt;span&gt;There is plenty of hopped wort left over in the bottom of the boiler to set aside for krausening&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Once the boiler level got
somewhat low I decided to take 1L of hopped wort to put in the
freezer ready to sanitise before bottling (called krausening). &lt;em&gt;Next
time once the boiler starts to run a lot slower I will call it a day 
and then pour the remainder from the top of the boiler (by tipping it
to the side, just before I clean it), staight into the recycled 
polypin bags I’m using to store it in the freezer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BLXlgymCUAAX5zW.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BLXlgymCUAAX5zW.jpg&quot; alt=&quot;Kettle after transfer to FV&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;after-the-transfer-via-the-heat-exchanger-to-the-fermentation-bucket-there-can-be-a-bit-of-foam-making-it-more-difficult-to-get-an-accurate-hydrometer-reading&quot;&gt;&lt;span&gt;After the transfer via the heat exchanger to the fermentation bucket there can be a bit of foam making it more difficult to get an accurate hydrometer reading&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;I had to use the hydrometer to push
some bubbles aside to try and get a clear head to get a reading, it
was not the best. &lt;em&gt;Next time I’ll be taking the reading from the
hopped wort that was left over in the bottom of the boiler that I’ll
then set that aside for my future krausening wort.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BLBpKovCQAAd0le.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BLBpKovCQAAd0le.jpg&quot; alt=&quot;Hops&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;accurate-measurements-of-final-volume-after-the-boil-is-important&quot;&gt;&lt;span&gt;Accurate measurements of final volume after the boil is important&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;I thought I could wing it with rough estimates based on the size of the
fermentation vessel. I’ve made marks on the side of the vessel for
this first gyle so will fill up with water once it’s empty to get the
accurate reading. &lt;em&gt;I will be making marks on a long plastic spoon that
correspond to various volumes in the 25L fermentation buckets I
have.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BLCUStsCMAANud6.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BLCUStsCMAANud6.jpg&quot; alt=&quot;Sparge&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;one-pass-counterflow-heat-exchange-is-slow&quot;&gt;&lt;span&gt;One-pass counterflow heat exchange is SLOW&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;The small heat-exchanger and cold water supply I have doesn’t cool the 
hopped wort quick enough. It was boring and a huge waste of time. &lt;em&gt;Next
time I will be recirculating the kettle through the heat exchanger
rather than going straight into the fermentation bucket – this way it
will cool quicker and I can have the flow at a higher rate due to it all
mixing in with the rest to cool all at once rather than solely on
the super slow flow rate.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;my-friends-who-have-chickens-will-have-to-come-fetch-the-spent-grain-afterwards&quot;&gt;&lt;span&gt;My friends who have chickens will have to come fetch the spent grain afterwards&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Because I’ll have had a few beers while brewing so won’t be able to
drive to drop it off before it spoils. I can also put it in the fridge
so it’s alright for the next day.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Gyle Zero – My First Attempt at Homebrewing</title>
   <link href="http://mokele.co.uk/2013/05/24/gyle-0.html"/>
   <updated>2013-05-24T00:00:00+01:00</updated>
   <id>http://mokele.co.uk/2013/05/24/gyle-0</id>
   <content type="html">&lt;style type=&quot;text/css&quot;&gt;
.brief {
  margin-top: 1em;
}
&lt;/style&gt;

&lt;div class=&quot;brief&quot;&gt;
&lt;p&gt;So here I am. I feel kinda stressed out, kinda relieved, a tad anxious.
It's all a bit of fun right? Good to hear. I (hopefully) brewed 
some beer today. The Safale S-04 should be doing its part of the 
bargain, I'll sneak a peak before I go to bed and try and not disturb 
them.&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;graphs-if-you-wait-for-them-to-load&quot;&gt;Graphs! (if you wait for them to load)&lt;/h2&gt;

&lt;p&gt;If you’ve read my &lt;a href=&quot;/2013/04/17/intro-brewing-beer-erlang-bootstrap-raspberry-pi.html&quot;&gt;previous entry&lt;/a&gt; on my homebrewing venture you’ll
see all of the fancy contraptions and things that I’ve been working
on… well, I didn’t really use much of that other than the digital
thermistor readouts. It was taking too long to get something I was happy
with, so decided to bite the bullet and get a brew done with a lot more
manual intervention, which turns out to be quite boring.&lt;/p&gt;

&lt;p&gt;I made a lot of mistakes and learnt a great deal about how I need to
change my kit to improve on this zeroth gyle. I’ll post more about that
soon. This is an end-of-brew-day signing-off post. Enjoy the graph!
:)&lt;/p&gt;

&lt;p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js&quot;&gt; {&quot;dataSourceUrl&quot;:&quot;//docs.google.com/a/mokele.co.uk/spreadsheet/tq?key=0Amz8p9f9sUNZdGdNclNsbnlXbDIxSWxMSEVIa2l0QVE&amp;transpose=0&amp;headers=1&amp;range=A1%3AJ9809&amp;gid=0&amp;pub=1&quot;,&quot;options&quot;:{&quot;displayAnnotations&quot;:true,&quot;vAxes&quot;:[{&quot;useFormatFromData&quot;:true,&quot;title&quot;:&quot;Left vertical axis title&quot;,&quot;minValue&quot;:null,&quot;logScale&quot;:false,&quot;viewWindow&quot;:{&quot;min&quot;:null,&quot;max&quot;:null},&quot;maxValue&quot;:null},{&quot;useFormatFromData&quot;:true,&quot;minValue&quot;:null,&quot;logScale&quot;:false,&quot;viewWindow&quot;:{&quot;min&quot;:null,&quot;max&quot;:null},&quot;maxValue&quot;:null}],&quot;titleTextStyle&quot;:{&quot;fontSize&quot;:16},&quot;booleanRole&quot;:&quot;certainty&quot;,&quot;title&quot;:&quot;Chart title&quot;,&quot;legend&quot;:&quot;right&quot;,&quot;wmode&quot;:&quot;opaque&quot;,&quot;hAxis&quot;:{&quot;useFormatFromData&quot;:true,&quot;title&quot;:&quot;Horizontal axis title&quot;,&quot;minValue&quot;:null,&quot;viewWindow&quot;:{&quot;min&quot;:null,&quot;max&quot;:null},&quot;maxValue&quot;:null},&quot;animation&quot;:{&quot;duration&quot;:0},&quot;width&quot;:800,&quot;height&quot;:500},&quot;state&quot;:{},&quot;view&quot;:{},&quot;isDefaultVisualization&quot;:true,&quot;chartType&quot;:&quot;AnnotatedTimeLine&quot;,&quot;chartName&quot;:&quot;Chart1&quot;} &lt;/script&gt;
&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Intro: Brewing Beer with Erlang, Bootstrap, and a Raspberry Pi</title>
   <link href="http://mokele.co.uk/2013/04/17/intro-brewing-beer-erlang-bootstrap-raspberry-pi.html"/>
   <updated>2013-04-17T00:00:00+01:00</updated>
   <id>http://mokele.co.uk/2013/04/17/intro-brewing-beer-erlang-bootstrap-raspberry-pi</id>
   <content type="html">&lt;style type=&quot;text/css&quot;&gt;
#post img {
  width: 450px;
  border: 1px solid #333;
  margin: 0 auto;
  display: block;
}
.brief {
  margin-top: 1em;
}
&lt;/style&gt;

&lt;div class=&quot;brief&quot;&gt;
&lt;p&gt;I've started working on a homebrewing controller and interface for the
purposes of:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;learning how to program things that interact with the real
  world&lt;/li&gt;
  &lt;li&gt;learn more about the processes involved in brewing beer&lt;/li&gt;
  &lt;li&gt;manage my homebrewing accurately as to easily measure and reproduce
  any changes I make between brews&lt;/li&gt;
  &lt;li&gt;brew good beer consistently and with minimal effort - this is the
most important bit right? :D sure is!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I started off with an &lt;a href=&quot;http://arduino.cc&quot;&gt;Arduino&lt;/a&gt;, 
&lt;a href=&quot;http://erlang.org/&quot;&gt;Erlang&lt;/a&gt;, and some custom Javascript,
but have now moved to &lt;a href=&quot;http://www.raspberrypi.org/&quot;&gt;Raspberry Pi&lt;/a&gt;
and &lt;a href=&quot;http://twitter.github.io/bootstrap/&quot;&gt;Bootstrap&lt;/a&gt;. The Erlang
side has stayed the same other than the Raspberry Pi related libraries :D
&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;whats-involved&quot;&gt;&lt;span&gt;What’s Involved&lt;/span&gt;&lt;/h2&gt;

&lt;h3 id=&quot;hardware&quot;&gt;&lt;span&gt;Hardware&lt;/span&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Raspberry Pi&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://proto-pic.co.uk/434mhz-rf-link-transmitter/&quot;&gt;RF Transmitter&lt;/a&gt; to control 3 wireless plug sockets&lt;/li&gt;
  &lt;li&gt;3 &lt;a href=&quot;http://proto-pic.co.uk/mini-photocell/&quot;&gt;Photocells&lt;/a&gt; to monitor the current state of the plug sockets&lt;/li&gt;
  &lt;li&gt;A number of OneWire &lt;a href=&quot;http://proto-pic.co.uk/temperature-sensor-waterproof-ds18b20/&quot;&gt;Waterproof Thermistors&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2 Cygnet Boilers (one for Mash and one for Hot Liquor Tank
and for the Boil)&lt;/li&gt;
  &lt;li&gt;some [false buttoms][] for the boilers&lt;/li&gt;
  &lt;li&gt;a counterflow heat exchange from &lt;a href=&quot;http://themaltmiller.co.uk/index.php?_a=viewProd&amp;amp;productId=404&quot;&gt;The Malt Miller&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Loads of tubing bought from &lt;a href=&quot;http://www.thehomebrewforum.co.uk/viewtopic.php?f=37&amp;amp;t=4820&quot;&gt;The Homebrew Forum&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Loads of brewing buckets&lt;/li&gt;
  &lt;li&gt;and a pump&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BIFQb6-CMAAcRKA.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BIFQb6-CMAAcRKA.jpg&quot; alt=&quot;It looks like
this&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;https://pbs.twimg.com/media/BIFQim9CQAAF3UT.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BIFQim9CQAAF3UT.jpg&quot; alt=&quot;It looks like
this&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Doesn’t it look a mess right now! :)&lt;/p&gt;

&lt;h3 id=&quot;software&quot;&gt;&lt;span&gt;Software&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;I define my kit, process, and recipe with a Javascript object dialect
defined with Protocol Buffers for easily understandable configuration
and simple interaction between Javascript and Erlang. The &lt;a href=&quot;https://github.com/mokele/gyle.kit/blob/master/kit.js&quot;&gt;kit repo&lt;/a&gt; 
looks a bit like this where I define what each point does and its neighbours:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;Gyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;kit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;points&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;neighbours&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;hasHose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;hose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Mash Tun&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;neighbours&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;hasKettle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;kettle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
               &lt;span class=&quot;na&quot;&gt;temperatureSensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
               &lt;span class=&quot;na&quot;&gt;powerController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
           &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This allows me to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Attribute actions and processes to specific vessels, pumps,
intersections, valves, and pipes.&lt;/li&gt;
  &lt;li&gt;Use the point graph to tell when a route includes a pump leading
to it being automatically turned on when necessary.&lt;/li&gt;
  &lt;li&gt;Draw a diagram of the kit on the screen labeling each point.&lt;/li&gt;
  &lt;li&gt;Track changes in my kit, processes, and recipes via git
repositories. &lt;strong&gt;&lt;em&gt;Fork this kit/process/recipe!&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The backend is written in Erlang and I can do things like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;gyle_hardware_io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;power&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;044&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PowerState&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;gyle_hardware_io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;power&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PowerState&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;onewire_therm_manager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;w1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;28-000004753e42&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;437&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1366&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;233345&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32572&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;Shell&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;therm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;w1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;28-000004753e42&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1366&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;233378&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;22579&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;Shell&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;therm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;w1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;28-000004753e42&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;062&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1366&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;233381&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;682590&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;Shell&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;therm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;w1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;28-000004753e42&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;312&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1366&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;233385&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;342572&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;show-me-show-meeee&quot;&gt;&lt;span&gt;Show me! show meeee!&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;It looks like this! My old interface ended up being horrible, and this
new &lt;a href=&quot;http://twitter.github.io/bootstrap/&quot;&gt;Bootstrap&lt;/a&gt; based one is awesomely lovely.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BIFKQioCQAAI2lL.png&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BIFKQioCQAAI2lL.png&quot; alt=&quot;It looks like this!&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The Power indicators show the state of the sockets that are either
on, or should be on and are currently off. In this case both 1 and 2
are on. Socket 0 is not on and is not supposed to be on, otherwise it
would be visable and red.&lt;/li&gt;
  &lt;li&gt;The Temperature indictors show the current states of each thermistor.
They will eventually show the rate and direction of change as well as
target temperatures e.g. for efficient boils and mash temperatures&lt;/li&gt;
  &lt;li&gt;The list to the left is a step-by-step list of each process involved,
all defined in the process Javascript describing the flow of liquid
and other ingredients (and even cleaning solution!) in the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;migrating-from-the-arduino&quot;&gt;&lt;span&gt;Migrating from the Arduino&lt;/span&gt;&lt;/h2&gt;

&lt;h3 id=&quot;the-hardware-side-of-things&quot;&gt;&lt;span&gt;The Hardware side of things&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/A97qsO1CQAA9lRA.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/A97qsO1CQAA9lRA.jpg&quot; alt=&quot;Arduino&quot; /&gt;&lt;/a&gt;
&lt;br /&gt;This is the Arduino I was previously using (^above).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pbs.twimg.com/media/BIFGww8CcAAc1B8.jpg&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/BIFGww8CcAAc1B8.jpg&quot; alt=&quot;Raspberry Pi&quot; /&gt;&lt;/a&gt;
&lt;br /&gt;And this is the new Raspberry Pi along with a lot more neat wiring
than before, since now I have the experience to know
exactly what I’m doing.&lt;/p&gt;

&lt;h3 id=&quot;the-software-side-of-things&quot;&gt;&lt;span&gt;The Software side of things&lt;/span&gt;&lt;/h3&gt;

&lt;p&gt;The code I had on the Arduino simply routed data directly down the
serial port to the Erlang code, so was super easy to migrate to
Raspberry Pi, well… sortof. I had to write:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mokele/pie&quot;&gt;pie&lt;/a&gt; Erlang bindings to [pihwm][] Raspberry Pi C interface&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mokele/pt2262&quot;&gt;pt2262.erl&lt;/a&gt; Erlang code to produce pt2262 encoded signal sequences where previously I used the
Arduino code made available by &lt;a href=&quot;http://rayshobby.net/?p=2427&quot;&gt;rayshobby.net&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mokele/onewire_therm&quot;&gt;onewire_therm&lt;/a&gt; Erlang code to grab data from OneWire Thermistors&lt;/li&gt;
  &lt;li&gt;a &lt;a href=&quot;https://github.com/omerk/pihwm/pull/2&quot;&gt;bugfix for pihwm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well that’s the intro. Hopefully I’ll show it all working and release
some more code soon. I haven’t even brewed with it yet! Been too busy
and enthused getting it all connected and designing the whole thing.
It’s great fun! I feel like a beer now but need to get to bed ready to brew
more beer at work tomorrow morning :) Bottoms up!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Property testing Javascript Go match variations</title>
   <link href="http://mokele.co.uk/2012/10/30/property-testing-javascript-go-match-variations.html"/>
   <updated>2012-10-30T00:00:00+00:00</updated>
   <id>http://mokele.co.uk/2012/10/30/property-testing-javascript-go-match-variations</id>
   <content type="html">&lt;div class=&quot;brief&quot; style=&quot;margin-top: 1em&quot;&gt;
&lt;p&gt;
The past couple of days I've managed to churn out 
&lt;a href=&quot;https://github.com/mokele/proper.js&quot;&gt;proper.js&lt;/a&gt; – some middleware between
Javascript and Erlang's &lt;a href=&quot;https://github.com/manopapad/proper&quot;&gt;PropEr&lt;/a&gt;
property-based testing framework (Now supports &lt;a href=&quot;http://www.quviq.com/&quot;&gt;QuviQ QuickCheck&lt;/a&gt;).
And it finally has a real-world use-case for a project
I'm actually working on! Games of Go! What else could it have been!
&lt;/p&gt;

&lt;p&gt;
The reason why I wrote proper.js in the first place was for this exact
set of tests that was becoming a massive pain in the ass to debug. Hold
on tight, or jump straight to 
&lt;a href=&quot;#the-juicy-property-based-tests&quot;&gt;the juicy property-based tests&lt;/a&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#match-and-moves-data-structure&quot;&gt;Match and moves
data-structure&lt;/a&gt; background on the data-structure I'm testing&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#traversing&quot;&gt;Traversing&lt;/a&gt; more on how I want to traverse
      the data-strcture&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#the-juicy-property-based-tests&quot;&gt;The juicy property-based tests&lt;/a&gt;
      get straight to the juicy bits&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#the-actual-property-test&quot;&gt;The actual property test I wanted to write&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#interpreting-failed-tests&quot;&gt;Interpreting failed tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;

&lt;p&gt;&lt;img class=&quot;experienceFocalPoint&quot; alt=&quot;Scene from A Beautiful Mind&quot; src=&quot;/images/abeautifulmindgo.jpg&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;match-and-moves-data-structure&quot;&gt;&lt;span id=&quot;match-and-moves-data-structure&quot;&gt;Match and moves data-structure&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;You can skip straight to &lt;a href=&quot;#the-juicy-property-based-tests&quot;&gt;the juicy property-based tests&lt;/a&gt;, but here is
some background on the data-structure I am testing.&lt;/p&gt;

&lt;p&gt;I have a data-structure in Javascript where a match has 0-many moves in
an array, and each of those moves may also have its own list of moves. Each
move has a move number that starts off at 1, and each list of moves
cannot have a move who’s next item is not the same number or 1
greater. Added to that, child moves must be of a greater number to the
parent.&lt;/p&gt;

&lt;p&gt;The reason I designed the data-structure this way rather than simply
adding all move number 2s into the moves list of the 1s, and 3s into the
moves of the 2s, and so on… was that my variations data structure is designed for
games with less variations than there are numbers of moves. In an
average game of Go there are more than 200 or 300 moves, so in that case
I do not want a 300 depth nested array, it would be better to
have a single depth array. This means the depth of my data-structure is
proportional to the number of variations rather than just the number of moves.&lt;/p&gt;

&lt;p&gt;For example these are valid:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and these are invalid:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 1 is out of sequence&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 3 cannot also contain 3&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This data structure allows the storage of games of [Go][] and move
variations/scenarios during a game that someone may wish to play out
and review.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;traversing&quot;&gt;&lt;span id=&quot;traversing&quot;&gt;Traversing&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;To traverse the match variations I create a VariationNavigator to
encapsulate this behaviour. It has 3 functions I’m going to test in
this post, they are:&lt;/p&gt;

&lt;h3 id=&quot;movemove&quot;&gt;&lt;span&gt;move(move)&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Add a move to the navigator and update the move pointer to that move.
If any moves with a larger move number are before it, push them all into
the moves list of the last child of the parent moves with the same
number of the one being inserted. This sounds weird, and is one of the
reasons I want property tests! This is strange logic and it needs it.&lt;/p&gt;

&lt;p&gt;For example inserting another move number 2 to the root match.moves list
which change this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;into this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &amp;lt;- move into previous 2&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// &amp;lt;- also moved into previous 2&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// &amp;lt;- the new entry&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;nextvariation&quot;&gt;&lt;span&gt;next(variation)&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Move to last of a specific move number, and if the index of the item we
are at exeeds the variation pointers move to the move.moves level and
continue moving forward from there.&lt;/p&gt;

&lt;h3 id=&quot;previous&quot;&gt;&lt;span&gt;previous()&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Decrement the pointer, and if we’re at the beginning of a list of moves,
move to parent move in its parent’s move list.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;now-the-juicy-property-based-tests&quot;&gt;&lt;span id=&quot;the-juicy-property-based-tests&quot;&gt;Now the juicy property-based tests!&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Right, now down to business.&lt;/p&gt;

&lt;p&gt;Here we define what it is to be an empty match, a stone, a point, a 
board_size, and a move.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emptyMatch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;move_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oneof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'BLACK'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'WHITE'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;point&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oneof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;board_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oneof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A move is the joining of a stone() and a point(size) that we’ve 
already defined above, so let’s use &lt;strong&gt;LET&lt;/strong&gt; to do this.&lt;/p&gt;

&lt;p&gt;You can read this type as the sentence:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Given any stone&lt;/li&gt;
  &lt;li&gt;and any point from a board of a give size&lt;/li&gt;
  &lt;li&gt;construct a move object with those properties&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
             &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;stone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;point&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The FORALL_MATCHES function below is more complicated, but helps define the most important
property, that of all matches with all move variations. Well not entirely, it doesn’t yet
insert moves into anywhere other then the match.moves level, but I have
yet to implement that part of the property before posting this entry.&lt;/p&gt;

&lt;p&gt;You can read this property as the sentence:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;For all board sizes and&lt;/li&gt;
  &lt;li&gt;all lists of possible moves&lt;/li&gt;
  &lt;li&gt;add all those moves with a possible move number to the VariationNavigator for that match.&lt;/li&gt;
  &lt;li&gt;Then finally return the results of the function f of the generated match and navigator.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;possible_move_numbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FORALL_MATCHES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FORALL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;board_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FORALL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FORALL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;possible_move_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                        &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emptyMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;navigator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;VariationNavigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;maxNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
                                &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;maxNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
                                &lt;span class=&quot;nx&quot;&gt;maxNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                                &lt;span class=&quot;nx&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;note&quot;&gt;&lt;span&gt;note:&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;In another language (e.g. Erlang) you may write this as a separate property named
‘match’ and use LET instead of FORALL and not take a function as an
argument. I have not done it this way because proper.js does not yet
support yielding an object property with javascript functions, since
this get stripped by erlang_js. I have plans to create a work around to
solve this issue, but it was easy enough to create this FORALL_MATCHES
function instead for now.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;now-the-actual-property-test-i-wanted-to-write-to-find-the-bug-im-looking-for&quot;&gt;&lt;span id=&quot;the-actual-property-test&quot;&gt;Now the actual property test I wanted to write to find the bug I’m looking for&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;This property can be read as the sentence:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Given all possible matches with variations&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;and all possible variation pointers to moves in those matches&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;e.g. [0, 3, 2] -&amp;gt; match.moves[0].moves[3].moves[2]&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;call navigator.next(variation) until it returns false&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;assert the next move is always 1 more than the previous&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;assert that we have not exceeded the indexes of the variation pointers&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;call navigator.previous() until it reaches the start again&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;check the move we’ve at is the same as the one while we moved
forward&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;finally assert that moving forward and moving backwards traversed
the same number of moves&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;Variation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;variation_walking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FORALL_MATCHES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FORALL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;variations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;variation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lastMove&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;forwards&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
                        &lt;span class=&quot;c1&quot;&gt;// FORWARDS&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;variation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                            &lt;span class=&quot;nx&quot;&gt;forwards&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastMove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                                &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastMove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                            &lt;span class=&quot;nx&quot;&gt;lastMove&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;nx&quot;&gt;forwards&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

                        &lt;span class=&quot;c1&quot;&gt;// assert that we've not gone beyond each variation pointer&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;variation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;variation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pointers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

                        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;previous&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;c1&quot;&gt;// BACKWARDS&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;previous&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;navigator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;previous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;previous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;forwardMove&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;forwards&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                            &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
                            &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deepEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;forwardMove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                            &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastMove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                            &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
                            &lt;span class=&quot;nx&quot;&gt;lastMove&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;c1&quot;&gt;// no more forward walked moves left&lt;/span&gt;
                        &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forwards&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;interpreting-failed-tests&quot;&gt;&lt;span id=&quot;interpreting-failed-tests&quot;&gt;Interpreting failed tests&lt;/span&gt;&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ pjs variation.js Variation
property Variation.props.variation_walking()
......................!
Failed: After 23 test(s).
[19]
[[{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:122},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:22},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;WHITE&quot;,&quot;point&quot;:15},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;WHITE&quot;,&quot;point&quot;:146},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;WHITE&quot;,&quot;point&quot;:13},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:217}]]
[[1,2,2,4,4,2]]
[[2,0]]

Shrinking ..........(10 time(s))
[9]
[[{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:0},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:0},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:0},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:0},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:0},{&quot;moves&quot;:[],&quot;stone&quot;:&quot;BLACK&quot;,&quot;point&quot;:0}]]
[[1,2,2,4,4,2]]
[[2,0]]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;What PropEr did was take the values it generated when the test failed,
and shrink them down to the smallest example that it can find that still
fails the same test. The first failure is after the “Failed: After 23
test(s)” line and the shrank example is after “Shrinking ..”. 
Each one of the 4 values represents each LET or FORALL list of properties,
and is the value that was generated that you can use to reproduce that
specific failure.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;[9] is [board_size()]&lt;/li&gt;
  &lt;li&gt;The list of moves [[{“moves”:[],”stone:”BLACK”..},..]] was generated with [array(move(size))]&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;[[1,2,2,4,4,2]] was the list of which move numbers to try [possible_move_numbers(moves.length)]. 
Note that it does not contain a 3, the test uses the minimum of the
possible move number and what the maximum the next move number can possibly be so far.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;and [[2,0]] was the variation to traverse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means the match looked like the code below, and traversing forward to move
numbers 3 (at pointers [2, 0]) and back again did not peform correctly.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moves&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Beats writing contrived examples right?&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;in-summary&quot;&gt;&lt;span id=&quot;summary&quot;&gt;In Summary&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;The most important thing to note about this now is that
given the example above and many other examples re-running the tests,
 I can now start debugging and hopefully fix the bug &lt;strong&gt;&lt;em&gt;for all
possible matches&lt;/em&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;em&gt;not just one contrived example I can think up&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you’d like to help out with &lt;a href=&quot;https://github.com/mokele/proper.js&quot;&gt;proper.js&lt;/a&gt; fork it and start hacking
away!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Javascript property-based testing</title>
   <link href="http://mokele.co.uk/2012/10/29/javascript-property-based-testing.html"/>
   <updated>2012-10-29T00:00:00+00:00</updated>
   <id>http://mokele.co.uk/2012/10/29/javascript-property-based-testing</id>
   <content type="html">&lt;p&gt;Having utilised property-based testing using the Erlang applications &lt;a href=&quot;http://proper.softlab.ntua.gr/&quot;&gt;PropEr&lt;/a&gt; 
and &lt;a href=&quot;http://www.quviq.com/&quot;&gt;QuviQ QuickCheck&lt;/a&gt;, I now have a weird drive to use
the same library in my Javascript code. So I decided to write some
middleware between &lt;a href=&quot;https://github.com/basho/erlang_js&quot;&gt;erlang_js&lt;/a&gt; and &lt;a href=&quot;http://proper.softlab.ntua.gr/&quot;&gt;PropEr&lt;/a&gt;/&lt;a href=&quot;http://www.quviq.com/&quot;&gt;QuviQ QuickCheck&lt;/a&gt;, that at the time of
this post has ?LET, ?FORALL, and and oneof support.&lt;/p&gt;

&lt;p&gt;The project lives over on GitHub at
&lt;a href=&quot;https://github.com/mokele/proper.js&quot;&gt;https://github.com/mokele/proper.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To test the array properties first build it:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;and run:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./properjs priv/array.js Array
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This example was written before &lt;code class=&quot;highlighter-rouge&quot;&gt;pjs&lt;/code&gt; was installable. Installation
instructions are on
&lt;a href=&quot;http://mokele.github.com/proper.js&quot;&gt;http://mokele.github.com/proper.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the above array example that adds a remove function to Array’s
prototype (from &lt;a href=&quot;http://stackoverflow.com/a/3955096/1562641&quot;&gt;stackoverflow&lt;/a&gt;) and tests an Array of incrementing positive integers does not
include an item after it is removed and that its length always decrements by 1.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;remove&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;min_max_pos_integer_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos_integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pos_integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;min_max_pos_integer_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FORALL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;min_max_pos_integer_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FORALL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;min_max_pos_integer_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So there it is, a preliminary version of property-based testing in
Javascript plugged directly into &lt;a href=&quot;http://proper.softlab.ntua.gr/&quot;&gt;PropEr&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While writing this post I found out &lt;a href=&quot;https://bitbucket.org/darrint/qc.js/&quot;&gt;qc.js&lt;/a&gt; exists, which is all well
and good, but oh well! I’m sure it’s great but I’m already set on
integrating directly with PropEr/QuickCheck rather than supporting an
entire fork.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Round Games of Go on a Round Goban</title>
   <link href="http://mokele.co.uk/2012/10/10/round-games-of-go-on-a-round-goban.html"/>
   <updated>2012-10-10T00:00:00+01:00</updated>
   <id>http://mokele.co.uk/2012/10/10/round-games-of-go-on-a-round-goban</id>
   <content type="html">&lt;p&gt;I’m working on a web based &lt;a href=&quot;http://en.wikipedia.org/wiki/Go_(game)&quot;&gt;Go&lt;/a&gt; client and server, and to aide in
abstracting out all the different &lt;a href=&quot;http://en.wikipedia.org/wiki/Rules_of_Go&quot;&gt;rules&lt;/a&gt; I decided to implement
&lt;a href=&quot;http://www.youdzone.com/go.html&quot;&gt;Round Go&lt;/a&gt; as “popularised” by Harald Schwarz. Well, the game is
pretty messed up to play and my brain gets pretty confused rather
quickly and has no idea yet what constitutes good opening strategy.&lt;/p&gt;

&lt;p&gt;I’ve open sourced the drawing of this board via HTML5 Canvas Element
over at &lt;a href=&quot;https://github.com/mokele/roundgoban&quot;&gt;https://github.com/mokele/roundgoban&lt;/a&gt;
– go nuts. I have.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://mokele.github.com/roundgoban/roundgoban.png&quot; alt=&quot;Round Goban&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I recently asked my friend Maribel over at 
&lt;a href=&quot;http://maribelmade.com/&quot;&gt;http://maribelmade.com/&lt;/a&gt;
for a new Sock Monkey for a another friend’s new baby girl, and was
pleasantly surprised when she asked for a hi-res version of the board to
hang on her wall. Well, that’s the main reason why this repository got
life. By adding some functional options to the board constructor you can
now do arty things like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;inner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;spiral&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;goban&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RoundGoban&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'#goban'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;outerCircle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;lineWidthMultiplier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;strokeStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#BBBBBB'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#BBBBBB'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spiral&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#555555'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spiral&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#AA0000'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spiral&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#FF0000'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#BBBBBB'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;http://mokele.github.com/roundgoban/roundgoban2.png&quot; alt=&quot;Round Goban&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Erlang, Protocol Buffers, and JSON...  epbj</title>
   <link href="http://mokele.co.uk/2012/10/05/erlang-protobufs-and-json.html"/>
   <updated>2012-10-05T00:00:00+01:00</updated>
   <id>http://mokele.co.uk/2012/10/05/erlang-protobufs-and-json</id>
   <content type="html">&lt;p&gt;I got fed up generating and manipulating proplists in my new Erlang project, and
realised I needed a generic &lt;a href=&quot;http://code.google.com/p/protobuf/&quot;&gt;Protocol Buffers&lt;/a&gt; to &lt;a href=&quot;http://www.json.org/&quot;&gt;JSON&lt;/a&gt; encoder decoder.
Well, there was nearly already one, and it’s called the erlang_protobufs
application. It parses .proto files and generates erlang records, so I’ve made
it also do record &amp;lt;-&amp;gt; proplists conversion. It’s the ‘json’ branch of &lt;a href=&quot;https://github.com/mokele/erlang_protobuffs/tree/json&quot;&gt;my fork
of erlang_protobufs&lt;/a&gt; and the full demo is at the &lt;a href=&quot;https://github.com/mokele/epbj/&quot;&gt;epbj demo repo&lt;/a&gt;, with the
&lt;a href=&quot;https://github.com/mokele/epbj/blob/master/include/pbj.proto&quot;&gt;.proto file here&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;table style=&quot;border-spacing: 0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot; style=&quot;text-align: right&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pbj_pb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jelly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;peanut_butter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sandwich&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sandwich_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PBJ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;#sandwich&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bread&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;'WHOLEMEAL'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ingredients&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;#ingredient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;peanut_butter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;#peanut_butter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;style&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;'COARSE'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;#ingredient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jelly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;#jelly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flavor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;'STRAWBERRY'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;#sandwich&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{...}&lt;/span&gt;

&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;JSON1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pbj_pb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;json_ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PBJ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bread&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WHOLEMEAL&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;slices&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ingredients&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;peanutButter&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;COARSE&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]}],&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jelly&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;flavor&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;STRAWBERRY&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]}]]}]&lt;/span&gt;

&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;JSON2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pbj_pb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;json_ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PBJ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sandwich&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bread&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WHOLEMEAL&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;slices&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ingredients&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;peanutButter&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;COARSE&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]}],&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jelly&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;flavor&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;STRAWBERRY&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]}]]}]}]&lt;/span&gt;

&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pbj_pb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sandwich&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;jsx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;jsx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;JSON1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))).&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;#sandwich&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bread&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;'WHOLEMEAL'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;ingredients&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;#ingredient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;peanut_butter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;#peanut_butter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;style&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;'COARSE'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                                     &lt;span class=&quot;n&quot;&gt;jelly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                         &lt;span class=&quot;nl&quot;&gt;#ingredient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;peanut_butter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;n&quot;&gt;jelly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;#jelly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flavor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;'STRAWBERRY'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}]}&lt;/span&gt;

&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pbj_pb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;jsx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;jsx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;JSON2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))).&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;#sandwich&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{...}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are a few current design decisions and notes, so here they are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;encoding named ‘json_ready’ because it itself is not yet json, it’s also a very specific
proplist that json encoders expect. This will surely change, this is the
first thing I came up with.&lt;/li&gt;
  &lt;li&gt;decoding named ‘from_props’&lt;/li&gt;
  &lt;li&gt;Uses named fields and enums and not integer representations due to not yet
wanting to generate any .js includes to more easily parse on the javascript
end. This will surely change as it evolves due to wanting to save on precious
bandwidth.&lt;/li&gt;
  &lt;li&gt;JSON names are camel cased&lt;/li&gt;
  &lt;li&gt;My .proto files name messages with _ naming convension (which is not what is
advised by the spec) because that is currently how I prefer my erlang records
to be named, and that is also how the erlang_protobufs app currently handles
those names. This is a work-around.&lt;/li&gt;
  &lt;li&gt;extensions are supported and saved in the “$extensions” key of the resulting
JSON. The parent message however is only ‘from_props’ decodable by the _pb
module that defined the extension. This is due to erlang_protobufs having two
types of value in the ‘$extensions’ dict {raw, binary()} and an actual value.
JSON decoding would require a third and a lot of other changes I am not yet
free to make.&lt;/li&gt;
  &lt;li&gt;I have changed string decoding to return binaries or else JSON encoding gets
confused and spits out lists of integers.&lt;/li&gt;
  &lt;li&gt;I’m sure there are more, watch this space…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The new project I’m working on is in no way related to sandwiches.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Rebar release upgrade caveats / gotchas (and fixes)</title>
   <link href="http://mokele.co.uk/2011/07/01/rebar-release-upgrade-caveats.html"/>
   <updated>2011-07-01T00:00:00+01:00</updated>
   <id>http://mokele.co.uk/2011/07/01/rebar-release-upgrade-caveats</id>
   <content type="html">&lt;p&gt;I’ve had to change a few things in &lt;a href=&quot;http://github.com/basho/rebar&quot;&gt;rebar&lt;/a&gt; to make release upgrades a little easier and less error prone for our projects here at &lt;a href=&quot;http://smarkets.com/&quot;&gt;Smarkets.com&lt;/a&gt;. They should be beneficial to everyone, but specifically those new to OTP release upgrades or those who’ve not read all the &lt;a href=&quot;http://www.erlang.org/doc/man/release_handler.html&quot;&gt;release documentation&lt;/a&gt; before jumping in at the deep end with rebar. Rebar is great at getting those new and experienced with Erlang on the right track, but the release upgrades have (read had) a number of caveats that can be big gotchas to those who haven’t built their own releases from scratch without rebar before going hell for leather.&lt;/p&gt;

&lt;p&gt;The caveats that I’ve found with the existing copy of rebar are thus:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The default in the reltool.config node template is to use archived libs which prevents you from being able to manage release upgrades&lt;/li&gt;
  &lt;li&gt;The default environment config in the node template is named app.config and is copied to your TargetDir/etc/ whereas a release upgrade requires this file be named sys.config and be located in TargetDir/releases/Vsn/ (see erlang/doc/man/&lt;a href=&quot;http://www.erlang.org/doc/man/config.html&quot;&gt;config&lt;/a&gt;) - if this is not the case then the entire application environment (application:get_env) will be wiped.&lt;/li&gt;
  &lt;li&gt;Hipe may get built and distributed into your release regardless of whether you use it and will cause errors when generating your first upgrade.&lt;/li&gt;
  &lt;li&gt;No TargetDir/releases/&lt;a href=&quot;http://www.erlang.org/doc/man/release_handler.html#create_RELEASES-4&quot;&gt;RELEASES&lt;/a&gt; file is generated causing your first release to have an empty application libs lists. If you upgrade from a version with an empty application libs list and then downgrade back to it and release_handler:remove_release the newer of the two then all applications directories along with erts will be deleted from the release libs directory.&lt;/li&gt;
  &lt;li&gt;temporary directories “releases” and “libs” are created when running generate-upgrade which prevents there from being existing directories with these names in the same directory as a reltool.config&lt;/li&gt;
  &lt;li&gt;sasl error_logger_mf can cause VM crashes when logging possibly large terms.&lt;/li&gt;
  &lt;li&gt;generate-upgrades looks in the same directory as reltool.config for the new and old versions instead of looking in target_dir and its parent directory. This causes an enoent file error if you have a target_dir that points elsewhere.&lt;/li&gt;
  &lt;li&gt;the default generate-appups instruction for module changes is {update..}, which is incorrect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These have been addressed by:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;adding the instruction to simplenode.reltool.config to not use archived libs.&lt;/li&gt;
  &lt;li&gt;updating the simplenode templates to refer to sys.config instead of app.config requiring the {{rel_vsn}} default overlay var addition used in simplenode.reltool.config&lt;/li&gt;
  &lt;li&gt;exclude hipe application by default in simplenode.reltool.config&lt;/li&gt;
  &lt;li&gt;call release_handler:create_RELEASES in generate-upgrade command&lt;/li&gt;
  &lt;li&gt;“releases” and “libs” temporary directories are placed in _tmp before being cleaned.&lt;/li&gt;
  &lt;li&gt;Remove error_logger_mf* from simplenode.sys.config. You should be using [riak_err][] or another alternative. There should be no default that has any possibility of crashing the VM.&lt;/li&gt;
  &lt;li&gt;generate-upgrades now looks for new and previous versions in the parent directory to target_dir instruction in reltool.config&lt;/li&gt;
  &lt;li&gt;changed {update..} to {load_module..} in generate-appups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These patches are available on the Smarkets &lt;a href=&quot;http://github.com/smarkets/rebar&quot;&gt;github account&lt;/a&gt; and have also been &lt;a href=&quot;https://github.com/smarkets/rebar/tree/sys-config&quot;&gt;split up&lt;/a&gt; into &lt;a href=&quot;https://github.com/smarkets/rebar/tree/upgrade-fixes&quot;&gt;separate&lt;/a&gt; &lt;a href=&quot;https://github.com/smarkets/rebar/tree/appup-load-module-fix&quot;&gt;branches&lt;/a&gt; ready for pull requests to the main &lt;a href=&quot;http://github.com/basho&quot;&gt;basho&lt;/a&gt; repo. You can follow the comments there once I’ve made those pull requests if you are interested to chime in / see whether any of this ever goes up-stream.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Release Upgrades with Rebar</title>
   <link href="http://mokele.co.uk/2010/11/23/release_upgrades_with_rebar.html"/>
   <updated>2010-11-23T00:00:00+00:00</updated>
   <id>http://mokele.co.uk/2010/11/23/release_upgrades_with_rebar</id>
   <content type="html">
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update: This post was a bit overly complex for rebar release upgrades.
The official rebar code now has upgrades in it’s 
&lt;a href=&quot;https://github.com/basho/rebar&quot;&gt;master branch&lt;/a&gt; and a 
&lt;a href=&quot;https://github.com/basho/rebar/wiki/Upgrades&quot;&gt;wiki page&lt;/a&gt;, 
so read that instead&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I originally wrote my own build-tool for Erlang/OTP projects, it was an 
amazing exercise in learning Erlang and specifically getting my head 
around OTP. If you’re starting to learn this stuff now, then I highly 
recommend spending a few weeks as I did working with everything manually 
instead of having the world magically work for you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you don’t understand how release upgrades/installs work already, 
then &lt;strong&gt;do not&lt;/strong&gt; read on and &lt;strong&gt;do not&lt;/strong&gt; use what I’m writing to aide you in 
doing anything of the sort, it’s probably a bad idea.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That aside, what I’ve done is taken the release upgrade helpers from my
original build tool and have started rewriting them into &lt;a href=&quot;https://github.com/basho/rebar&quot;&gt;basho’s rebar 
build-tool&lt;/a&gt;. The outcome of this is I’ve
added the &lt;strong&gt;gen-relup&lt;/strong&gt; command which fetches a release’s &lt;strong&gt;boot_rel’s&lt;/strong&gt; 
&lt;strong&gt;.rel&lt;/strong&gt; file from a &lt;strong&gt;git&lt;/strong&gt; ref specified by a tag along with the 
associated &lt;strong&gt;.app&lt;/strong&gt; files so that it can then run &lt;strong&gt;systools:make_relup&lt;/strong&gt; 
and give you a nice &lt;strong&gt;relup&lt;/strong&gt; file containing the necessary instructions 
gathered from your &lt;strong&gt;.appup&lt;/strong&gt; files. I’ve also patched &lt;strong&gt;generate&lt;/strong&gt; so 
that it copies this to your new &lt;strong&gt;releases/Vsn&lt;/strong&gt; directory along with 
&lt;strong&gt;start.boot&lt;/strong&gt; and &lt;strong&gt;sys.config&lt;/strong&gt; (have renamed and moved this from 
app.config due to more accurately fitting the &lt;a href=&quot;http://www.erlang.org/doc/design_principles/release_structure.html&quot;&gt;OTP design principles for 
releases&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code is available on the &lt;strong&gt;release_updates&lt;/strong&gt; branch of &lt;a href=&quot;https://github.com/mokele/rebar&quot;&gt;my github 
fork&lt;/a&gt;, and here’s how to use it (my 
example project is named ‘pointless’ and is exactly that, and useless too):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;mokele:pointless steve&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./rebar compile gen-relup &lt;span class=&quot;nv&quot;&gt;upfrom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;v3 generate
&lt;span class=&quot;gp&quot;&gt;==&amp;gt; &lt;/span&gt;rel &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;compile&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;==&amp;gt; &lt;/span&gt;pointless &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;compile&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;==&amp;gt; &lt;/span&gt;rel &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;gen-relup&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;==&amp;gt; &lt;/span&gt;rel &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;generate&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What this will do is:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;compiled as normal&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;git show refs/tags/v3:rel/pointless.rel &amp;gt; rel/pointless-v3.rel&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;mkdir ebin/v3/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;git show refs/tags/v3:ebin/pointless.app &amp;gt; ebin/v3/pointless.app&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;pre&amp;gt;systools:make_relup(&quot;rel/pointless.rel&quot;,
  [&quot;rel/pointless-v3.rel&quot;], [&quot;rel/pointless-v3.rel&quot;],
  [{path, [&quot;ebin&quot;, &quot;ebin/v3&quot;]}])&amp;lt;/pre&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;generate release as normal&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;cp rel/sys.config {{target_dir}}/releases/4/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;cp rel/relup {{target_dir}}/releases/4/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;cp {{target_dir}}/releases/4/pointless.boot &lt;/code&gt;
  &lt;code&gt;  {{target_dir}}/releases/4/start.boot &lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;cp {{target_dir}}/releases/4/pointless.rel rel/pointless.rel&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the moment this requires that you add the &lt;strong&gt;.rel&lt;/strong&gt; file associated
with the &lt;strong&gt;boot_rel&lt;/strong&gt; value from your &lt;strong&gt;reltool.config&lt;/strong&gt; into git under 
your reltools directory (the one that was last copied in the list above),
and also add the &lt;strong&gt;.app&lt;/strong&gt; files that might have been generated from 
&lt;strong&gt;.app.src&lt;/strong&gt; files into git also, otherwise it would have to check out the 
.src file and regenerate the older version’s .app file, which I didn’t feel
was worth it, plus I’d like to keep a snapshot of the exact .app and .rel 
files associated with a release anyways, incase the a future version of 
rebar changes something I am unaware of. These files must exist in your 
git repository &lt;strong&gt;for the tag specified in the upfrom argument&lt;/strong&gt;, otherwise
it’ll most probably fail to create a useful relup file or create one at all.&lt;/p&gt;

&lt;p&gt;If you’re happy with the relup file then you can go ahead and do a test 
run of your install. One thing I do for this is &lt;a href=&quot;http://www.kernel.org/pub/software/scm/git/docs/git-stash.html&quot;&gt;git stash&lt;/a&gt; my changes
for the new version then compile and generate my older release and copy it
to &lt;strong&gt;rel/test_pointless&lt;/strong&gt; (again maintaining my pointless project and release
names). Then after this I can &lt;strong&gt;git stash pop&lt;/strong&gt; my potential new version,
compile, gen-relup, and generate it, then I can do the ugly business.&lt;/p&gt;

&lt;p&gt;Another update I have made to the &lt;strong&gt;generate&lt;/strong&gt; command is to have it also 
generate me a &lt;a href=&quot;http://www.erlang.org/doc/man/release_handler.html#create_RELEASES-4&quot;&gt;&lt;strong&gt;RELEASES&lt;/strong&gt;&lt;/a&gt; file with &lt;em&gt;relative paths to ebin directories&lt;/em&gt;.
What this means is you’ll still be able to move your generated release’s 
directory around without a problem, but the downside is that you can’t use 
&lt;strong&gt;release_handler:unpack_release&lt;/strong&gt; anymore, since that will put full 
path’s in the &lt;strong&gt;RELEASES&lt;/strong&gt; file for your new release. You can if you really
want and don’t mind pull paths once you’ve got your release running somewhere
where it’s never going to get moved. In that case you can zip up your new 
release directory and go nuts.&lt;/p&gt;

&lt;p&gt;But if you want to maintain relative paths in your &lt;strong&gt;RELEASES&lt;/strong&gt; file then 
you’ll need to use &lt;strong&gt;release_handler:set_unpacked&lt;/strong&gt; and then install like 
so (I’d like to automate this stuff too at some point):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;mokele:pointless steve&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cp -r rel/pointless/lib/pointless-4 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                              rel/test_pointless/lib/pointless-4
mokele:pointless steve&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cp -r rel/pointless/releases/4 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                              rel/test_pointless/releases/4
mokele:pointless steve&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;rel/test_pointless/
mokele:pointless steve&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bin/pointless attach&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;release_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set_unpacked&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;./releases/4/pointless.rel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pointless&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;./lib/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]).&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;release_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;install_release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[]}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;release_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make_permanent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;well that’s it for now. Hopefully I keep improving on this and end up putting 
a pull request into basho’s repository, but for now you can check it out on 
&lt;a href=&quot;https://github.com/mokele/rebar&quot;&gt;my github account&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>You can do release upgrades with inet booted clients</title>
   <link href="http://mokele.co.uk/2010/11/20/you-can-do-release-upgrades-with-inet-booted-clients.html"/>
   <updated>2010-11-20T00:00:00+00:00</updated>
   <id>http://mokele.co.uk/2010/11/20/you-can-do-release-upgrades-with-inet-booted-clients</id>
   <content type="html">&lt;p&gt;&lt;em&gt;Update&lt;/em&gt; – The &lt;a href=&quot;https://github.com/mokele/otp/commit/f73018ab6ccbec613aaeea5942146ca50d82702b&quot;&gt;patch&lt;/a&gt; discussed in this post has since been &lt;a href=&quot;http://www.erlang.org/download/otp_src_R14B03.readme&quot;&gt;accepted&lt;/a&gt; into &lt;a href=&quot;http://www.erlang.org/download/&quot;&gt;OTP/R14B03&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While learning &lt;a href=&quot;http://erlang.org/&quot;&gt;Erlang/OTP&lt;/a&gt; I came across &lt;a href=&quot;http://wagerlabs.com/setting-up-erlang-on-amazon-ec2on-ec2&quot;&gt;these&lt;/a&gt; &lt;a href=&quot;http://wagerlabs.com/upgrading-your-erlang-cluster-on-amaz&quot;&gt;two&lt;/a&gt; posts by &lt;a href=&quot;http://wagerlabs.com/&quot;&gt;Joel Reymont&lt;/a&gt;, which helped a great deal in getting started using &lt;strong&gt;-loader inet&lt;/strong&gt; to remotely boot a client node which doesn’t have any of the necessary code available to it directly on its own disk, it all gets magically downloaded from the master server. How nice!&lt;/p&gt;

&lt;p&gt;A problem that I had though was the follow code snippet that Joel offered:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;table style=&quot;border-spacing: 0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot; style=&quot;text-align: right&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nf&quot;&gt;load_modules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nf&quot;&gt;load_modules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Mod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;purge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Mod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;soft_purge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Mod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Mod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;nn&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Mod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;load_modules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;which I really didn’t feel happy using, considering it side-stepped the OTP &lt;strong&gt;release_handler&lt;/strong&gt; design principles, so made me feel rather dirty. So I went about figuring out how to do a proper &lt;strong&gt;release_handler:install_release&lt;/strong&gt; whenever I wanted to push new live code upgrades to nodes that don’t necessarily have a disk of their own. Wouldn’t that be nice.&lt;/p&gt;

&lt;p&gt;After finding and fixing the few places in [release_handler.erl and release_handler_1.erl][] that incorrectly tried to access the local disk for your code upgrades as apposed to using &lt;strong&gt;rpc&lt;/strong&gt; or [erl_prim_loader][] like it was supposed to, I actually found it to be rather easy, and very similar to a regular &lt;strong&gt;release_handler:install_release&lt;/strong&gt; that you might be used to.&lt;/p&gt;

&lt;p&gt;The first thing to note is that when referring to the nodes that have been booted using &lt;strong&gt;-loader inet&lt;/strong&gt; we need a unique &lt;strong&gt;releases&lt;/strong&gt; directory for each one, or else OTP will get very confused about which running release it’s upgrading. For the &lt;strong&gt;boot_server&lt;/strong&gt; you have started with &lt;a href=&quot;http://www.erlang.org/doc/man/erl_boot_server.html&quot;&gt;erl_boot_server:start&lt;/a&gt; or using the &lt;a href=&quot;http://www.erlang.org/doc/man/kernel_app.html&quot;&gt;kernal app config&lt;/a&gt; you’ll have the regular &lt;strong&gt;releases&lt;/strong&gt; directory for your node. I suggest using &lt;a href=&quot;github.com/basho/rebar/&quot;&gt;rebar&lt;/a&gt; to make sure you’re doing this right, but &lt;strong&gt;this is not the releases directory your booted clients should be using&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;directory-structure-of-your-master-node&quot;&gt;&lt;span id=&quot;directory-structure&quot;&gt;Directory structure of your master node&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Following the &lt;a href=&quot;http://www.erlang.org/documentation/doc-5.8/doc/design_principles/release_structure.html&quot;&gt;Release Structure Design Principles&lt;/a&gt; under &lt;strong&gt;Disk-Less and/or Read-Only Clients&lt;/strong&gt;, you’ll need something like the following (where the ClientNames are your node names e.g. diskless1@hostname, diskless2@hostname, etc):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ROOT/...
    /clients/ClientName1/bin
                        /releases/Vsn
            /ClientName2/bin
                        /releases/Vsn
            ...
            /ClientNameN/bin
                        /releases/Vsn&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you’re doing this manually you can copy the &lt;strong&gt;releases&lt;/strong&gt; and &lt;strong&gt;bin&lt;/strong&gt; for your diskless release, otherwise I propose writing an automated solution for when you connect/boot new nodes, or maybe this is something &lt;a href=&quot;github.com/basho/rebar/&quot;&gt;rebar&lt;/a&gt; could be doing in a special case when generating new node skeletons. You could make the diskless release the same as the boot server release, but again, be clear not to get confused between your clients’ releases directory and that of your boot server. The reason for this is because &lt;strong&gt;release_handler&lt;/strong&gt; needs to keep track of each of your clients and boot server independently, it does this using the files &lt;strong&gt;start_erl.data&lt;/strong&gt; and &lt;a href=&quot;http://www.erlang.org/doc/man/release_handler.html#create_RELEASES-4&quot;&gt;&lt;strong&gt;RELEASES&lt;/strong&gt; for each node, which you’ll need to create&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;starting-up-your-release&quot;&gt;&lt;span id=&quot;starting-up-your-release&quot;&gt;Starting up your release&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Now that we’ve got the right directory structure for our clients we can start them up:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;127.0.0.1 &lt;span class=&quot;c&quot;&gt;# the ip address of your boot server&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;diskless1@hostname
erl -loader inet -hosts &lt;span class=&quot;nv&quot;&gt;$HOST&lt;/span&gt; -id &lt;span class=&quot;nv&quot;&gt;$ID&lt;/span&gt; -name &lt;span class=&quot;nv&quot;&gt;$ID&lt;/span&gt; -setcookie samecookie &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  -boot /full/path/to/your/node/clients/diskless1@hostname/releases/1/start &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  -config /full/path/to/your/node/clients/diskless1@hostname/releases/1/sys&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Where our sys.config looks like so (and boot_server@hostname is our inet boot server):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sasl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;masters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;boot_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/full/path/to/your/node/clients/diskless1@hostname/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;releases_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/full/path/to/your/node/clients/diskless1@hostname/releases/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;http://www.erlang.org/doc/man/sasl_app.html&quot;&gt;Read about these &lt;strong&gt;sasl&lt;/strong&gt; app configuration options on erlang.org&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;release_handlerinstall_release1&quot;&gt;&lt;span id=&quot;release-install&quot;&gt;release_handler:install_release/1&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Now you’re good to go! By manually unpacking the releases/NewVSN directory to your client’s path (containing the required &lt;a href=&quot;http://www.erlang.org/doc/design_principles/release_handling.html#relup&quot;&gt;relup file&lt;/a&gt;!) and each of the new libs required to the boot server’s lib path (with the necessary &lt;a href=&quot;http://www.erlang.org/doc/man/appup.html&quot;&gt;app files&lt;/a&gt;!), you can now run &lt;a href=&quot;http://www.erlang.org/doc/man/release_handler.html#set_unpacked-2&quot;&gt;release_handler:set_unpacked&lt;/a&gt; then &lt;strong&gt;release_handler:install_release&lt;/strong&gt; on your inet booted node. It’s also possible to keep release specific libs inside a lib directory within each &lt;strong&gt;client_directory&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diskless1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;release_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set_unpacked&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;/full/path/to/your/node/clients/diskless1@hostname/releases/2/myrelease.rel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myapp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/full/path/to/your/node/lib/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diskless1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;release_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;install_release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[]}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diskless1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;release_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make_permanent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;ok&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diskless1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;release_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;which_releases&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myrelease&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;kernel-2.14.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stdlib-1.17.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myapp-2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;permanent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myrelease&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;kernel-2.14.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stdlib-1.17.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myapp-1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;sync_nodes&quot;&gt;&lt;span id=&quot;sync_nodes&quot;&gt;sync_nodes&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Actually, we’re not quite done yet. There’s one brilliant feature OTP provides that we haven’t yet made use of, and that’s release installs with &lt;strong&gt;sync_nodes&lt;/strong&gt;. When we have more than one node running the same version of a release, we need to synchronise the release install between all of these nodes. This &lt;strong&gt;appup&lt;/strong&gt; and &lt;strong&gt;relup&lt;/strong&gt; instruction is briefly explained in the &lt;a href=&quot;http://www.erlang.org/doc/man/appup.html&quot;&gt;appup docs&lt;/a&gt; and &lt;a href=&quot;http://www.erlang.org/doc/design_principles/release_handling.html#relup&quot;&gt;relup docs&lt;/a&gt;. What this does is to halt all the nodes specified in the nodes list when they each reach this instruction, all of which then contact one another and wait until the very last one has also reached this point. After this they all resume and the installation is sync’d like magic.&lt;/p&gt;

&lt;p&gt;In the example above the &lt;strong&gt;myapp.appup&lt;/strong&gt; and subsequently the &lt;strong&gt;relup&lt;/strong&gt; for &lt;strong&gt;myrelease&lt;/strong&gt; vsn 2 will contain an instruction along the lines of the following (along with the other load_modules and other instructions your update requires):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sync_nodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shared_id_atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diskless1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diskless2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diskless3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When your &lt;strong&gt;relup&lt;/strong&gt; involves this instruction it will &lt;em&gt;halt forever&lt;/em&gt; unless all nodes also reach this point, so be careful. I’m not entirely sure of the best practice in dealing with nodes that are down or don’t reach there, so if someone knows then that’d be a great addition to this point.&lt;/p&gt;

&lt;p&gt;ok, there we go. Something that might be described as an explanation of how to do release upgrades on and across inet booted client nodes. &lt;em&gt;If only there was something to automate the creation and upgrading of possibly a lot of nodes&lt;/em&gt;. &lt;em&gt;*&lt;strong&gt;faints&lt;/strong&gt;*&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Post Revisions with Jekyll</title>
   <link href="http://mokele.co.uk/2010/11/19/post-revisions-with-jekyll.html"/>
   <updated>2010-11-19T00:00:00+00:00</updated>
   <id>http://mokele.co.uk/2010/11/19/post-revisions-with-jekyll</id>
   <content type="html">&lt;p&gt;&lt;em&gt;Note: this post is now hosted by GitHub so this extension to Jekyll is
not available and visible on this post&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you can see to the right of this text, there’s a link to a page that shows the difference between the current version of this post and that of the previous version(s). It will include the addition of the introductory paragraph you are reading right now that I added after committing the rest below.&lt;/p&gt;

&lt;p&gt;Yesterday after getting some of my previous posts imported and rendered onto &lt;em&gt;mokele.co.uk&lt;/em&gt; using &lt;a href=&quot;http://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, I realised I’d never felt more happy setting up a new blog engine (of sorts). If you haven’t already, you already know you’ve put it off too long, so do it now. I can’t explain this entirely, but I think it might be down to the confidence I didn’t realise I had in hosting a site made entirely of static files; it’s quite a weight of my shoulders.&lt;/p&gt;

&lt;p&gt;That said, an obvious downside to Jekyll is the absence of dynamic content. If one was to add the possibility of on-request dynamic content it would definitely kill its elegance, and we’d have to think very carefully about how to do it without simply &lt;a href=&quot;http://www.doingitwrong.com/&quot;&gt;doing it wrong&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s still an interesting thing to think about, and after you realise it’s dynamic already through the git commits you’re making (followed by the static file generation), then maybe it isn’t so hard to think about how best to extend it to meet more needs.&lt;/p&gt;

&lt;p&gt;Following on from this idea (I’m not sure why I decided to do it, but it was still fun), I’ve &lt;a href=&quot;https://github.com/mokele/jekyll&quot;&gt;forked Jekyll&lt;/a&gt; and have made it possible to embed the git revision histories of your posts into their rendered pages, something that would have previously been developed as truly on-request dynamic functionality. (it also requires my fork of &lt;a href=&quot;https://github.com/mokele/ruby-git&quot;&gt;ruby-git&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jekyll --revisions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What this does is to add the list &lt;strong&gt;page.revisions&lt;/strong&gt; to the templates of each post, and to generate pages for each commit involving each post. So what I’ve done is added the following snippet to my post.html template:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;{% if page.revisions %}
&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;revisions&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Changes to this Post&lt;span class=&quot;nt&quot;&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  {% for revision in page.revisions %}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ revision.date | date: &quot;%d %B %Y&quot; }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&amp;lt;br&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ revision.url }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ revision.message }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  {% endfor %}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;  
{% endif %}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As well as this it will need the file &lt;strong&gt;_layouts/revision.html&lt;/strong&gt; to define the layout for each changeset diff page. By accessing &lt;strong&gt;diff.patch&lt;/strong&gt;, &lt;strong&gt;diff.message&lt;/strong&gt;, and &lt;strong&gt;diff.date&lt;/strong&gt; in this template you can display a nice little diff page. You should look on github at &lt;a href=&quot;https://github.com/mokele/mokele.co.uk/blob/master/_layouts/revision.html&quot;&gt;my revision.html&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;in-summary&quot;&gt;&lt;span id=&quot;summary&quot;&gt;In Summary&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Having a visible revision history for each post is an interesting idea, considering it would enable you to treat your blog as more of a wiki than a static set of posts, and could also be used to do things such as update the &lt;strong&gt;updated&lt;/strong&gt; tag in your &lt;strong&gt;atom.xml&lt;/strong&gt; or other generated feed. It’s simply an extension to Jekyll that doesn’t break the concept and makes use of the git log for your posts, and maybe there’s more to be done around making it more dynamic, but I know what I’m not going to be doing, making it require server-side logic for page requests.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Last.fm Semantic URI Routing / Rewriting</title>
   <link href="http://mokele.co.uk/2009/03/02/lastfm-semantic-uri-routing-rewriting.html"/>
   <updated>2009-03-02T00:00:00+00:00</updated>
   <id>http://mokele.co.uk/2009/03/02/lastfm-semantic-uri-routing-rewriting</id>
   <content type="html">&lt;p&gt;We’ve always been big on semantic URIs here at Last.fm, and I don’t think that’ll ever change (if not just due to not wanting to crush our google rank by screwing up any missing permanent redirects). Apache mod_rewrite has been a staple in the Audioscrobbler and Last.fm dev toolkit for many years, and we still use it now and again for webservices and some legacy bits and bobs, but it was getting rather annoying in cases where we wanted to reuse controllers for many different routing paths.&lt;/p&gt;

&lt;p&gt;Consider these 2 URLs:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.last.fm/music/Dananananaykroyd/+events&quot;&gt;http://www.last.fm/music/Dananananaykroyd/+events&lt;/a&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.last.fm/user/mokele/events&quot;&gt;http://www.last.fm/user/mokele/events&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although the URLs are completely different apart from the word “events” the resulting controller action and template we want to end up on is actually the same.  All that changes in this example is the request context which is written back to the Request along the path of parsing the URI from left to right.&lt;/p&gt;

&lt;p&gt;The way this is done is by controller delegation through the concept of Routes and Rewriters.&lt;/p&gt;

&lt;p&gt;Below is a massive flow diagram of Routing and Rewriting for the Last.fm Radiohead Wiki editing page, and after that we’ll talk more indepth about what’s actually going on in plain English.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.last.fm/music/Radiohead/+wiki/edit&quot;&gt;http://www.last.fm/music/Radiohead/+wiki/edit&lt;/a&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// from /www/index.php
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'music'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'namespace'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'music'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// from /music/musiccontroller.class.php
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Rewriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'$noredirect$artistname/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'noredirect'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'(\+noredirect\/|)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'artistname'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'((?!\+)(.[^\/]*))'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'controller'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'artist'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'artistname'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// from /music/artistcontroller.class.php
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Rewriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'+'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'wiki'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'action'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'view'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now here’s the same with loads of weird lines in describing the flow of terms&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// -&amp;gt; /www/index.php
&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;There&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;are&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;no&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Rewriters&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FrontController&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Routes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
 
   &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;music&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Radiohead&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wiki&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;edit&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;____&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_________&lt;/span&gt;
           &lt;span class=&quot;nx&quot;&gt;__&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'music'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'namespace'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'music'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_____&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                       &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_____&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
              &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                             &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;_____\____________________________&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
         &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
       &lt;span class=&quot;nx&quot;&gt;__&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;___&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// -&amp;gt; /music/musiccontroller.class.php
&lt;/span&gt; 
&lt;span class=&quot;sd&quot;&gt;/**
 * The default behaviour for naming a controller is the name of the matched route.
 * You can also override this behaviour by supplying a 'action' =&amp;gt; 'my' which would
 * end up finding mycontroller.class.php.
 * From this point on the logic of 'find first Rewriter match then first Route match'
 * repeats each time a controller file changes. (indicated by -&amp;gt;)
 */&lt;/span&gt;
 
   &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Radiohead&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wiki&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;edit&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_________&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;
 
&lt;span class=&quot;nx&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;defaulted&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;separated&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;URI&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Rewriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'$noredirect$artistname/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'noredirect'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'(\+noredirect\/|)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                         &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_______________&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
                             &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;noredirect&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;param&lt;/span&gt;

        &lt;span class=&quot;s1&quot;&gt;'artistname'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'((?!\+)(.[^\/]*))'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_______&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
                                  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;artistname&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;param&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'controller'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'artist'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
                        &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;______&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
                               &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;                        &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
                            &lt;span class=&quot;nx&quot;&gt;___\__&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
                          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
                          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'artistname'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;above&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;                             &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;_______________&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
               &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
             &lt;span class=&quot;nx&quot;&gt;__&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;___&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// -&amp;gt; /music/artistcontroller.class.php
&lt;/span&gt; 
   &lt;span class=&quot;o&quot;&gt;/+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wiki&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;edit&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_____&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Rewriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'+'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 
&lt;span class=&quot;sd&quot;&gt;/**
 * Rewriters take the full URI, match it and save it back without what it matched
 * so this basically just strips the +
 */&lt;/span&gt;
 
   &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wiki&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;edit&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;____&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;______&lt;/span&gt;
           &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'wiki'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'action'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'view'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;____&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;____&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;___&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                          &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;
       &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// -&amp;gt; /wikicontroller.class.php
&lt;/span&gt; 
&lt;span class=&quot;sd&quot;&gt;/**
 * If /edit was *missing* from the url then the current action would be 'view'.
 * The default action when it runs out of url to parse is 'overview'
 */&lt;/span&gt;
 
   &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;edit&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;____&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now that we’ve got the amazingly awesome looking crazy ASCII flow diagram out of the way let’s explain a little more about what the hell we’re actually doing!&lt;/p&gt;

&lt;p&gt;The first step is done by the front controller which has a list of global Routes that it will try and match against the first ‘/’ separated token of the request URI.  When it finds it the Route will tell it which namespace and controller to delegate to.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$routes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'user'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'namespace'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'user'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'group'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'namespace'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'group'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'about'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//... etc
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//construct front controller etc here
&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now when a request comes in to any URI starting with /about it will match the 3rd of our Routes and get delegated to the about controller.&lt;/p&gt;

&lt;p&gt;Now that we’re out of the front controller the next steps repeat until the whole URI has been parsed.  Each controller has it’s own list of Rewriters and Routes of which it may have none.  We then run through each Rewriter and see if it matches the URI.  The whole URI is used for this, which is unlike Routes which only match against the next URI token, and Rewriters also use a regular expression to match the URI as apposed to a static string for Routes.  Everything matched will be chomped off of the URI before any subsequent controller delegation.  This is the time at which request parameters can be grabbed and assign to the request with a given name.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// usercontroller.class.php
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$rewriters&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Rewriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'$username/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For URIs such as /user/mokele this Rewriter will end up matching and assigning the ‘username’ request parameter since ‘mokele’ matches the default regex ([^\/]+), and we always shove a slash on the end of URIs after the request comes in when using Routes and Rewriters.&lt;/p&gt;

&lt;p&gt;Now that we’ve got the name of the user the user controller will construct that user by it’s name and assign it back to the request for itself and possible controller delegates to fetch.&lt;/p&gt;

&lt;p&gt;If a Rewriter matches and it has a ‘controller’ parameter then this next Routing step is skipped.  Now that we’ve done the Rewriting step we move back to the Routing step for the user controller.  We do exactly the same as the front controller did and match against the first token of the rest of the URI that we have left to parse.  The difference here is that if nothing is matched then this token will become our controller action at which point delegation ends.  If there is no URI left to parse then the action will be the default which is ‘overview’.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/user/mokele&lt;/code&gt;
  ‘overview’ action&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/user/mokele/overview&lt;/code&gt;
  ‘overview’ action again&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/user/mokele/tags&lt;/code&gt;
  matches no routes so goes to the ‘tags’ action&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/user/mokele/events&lt;/code&gt;
  match the ‘events’ route and delegate to the the events controller with action ‘overview’ and a context of the User ‘mokele’&lt;/p&gt;

&lt;p&gt;This is the end of the delegation logic. If we’ve delegated at any point we start the process again until we have no URI left to parse.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;in-summary&quot;&gt;&lt;span id=&quot;summary&quot;&gt;In Summary&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;By doing URI parsing this way we’ve created clear separation of logic dependent on each token or segment of the URI.  The front controller decided the first bit, the user controller decided that ‘mokele’ is a username and that a User object should be constructed with it, and so on.  It also doesn’t require an Apache restart for changes to take effect, definitely a big win.&lt;/p&gt;

&lt;p&gt;Finally, the one Apache mod_rewrite configuration we need to add is this: (and before you start trying… index.php is only one of a few files in our document root)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-apacheconf&quot; data-lang=&quot;apacheconf&quot;&gt;RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
 </entry>
 

</feed>