<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:base="https://blog.many-monkeys.com" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Monkey See, Monkey Do; occasionally monkey learn.</title>
    <link>https://blog.many-monkeys.com</link>
    <atom:link href="https://blog.many-monkeys.com/rss.xml" rel="self" type="application/rss+xml" />
    <description>random posts from a semi-sentient simian</description>
    <language>en</language>
    <item>
      <title>This is an Elephant!</title>
      <link>https://blog.many-monkeys.com/posts/this-is-an-elephant/</link>
      <description>&lt;p&gt;First, I am no AI expert. Yeah, I did some neural network stuff at university in the 90&#39;s with some Kohonen self-organizing maps and 3-layer back propagation networks using a network of transputers etc but these are nothing compared to the behemoths of todays AI systems. You could easily train and run our neural networks on modern phones in a fraction of the time it took us then.&lt;/p&gt;
&lt;p&gt;As a software developer in today&#39;s world we are now expected to embrace AI to help us produce code faster etc, but if you are like me you get frustrated, not at what it can do which is impressive at times, but when it screws up and you feel the task has become harder. There is nothing more annoying as a response like &amp;quot;Yes, you are absolutely right&amp;quot; when you correct the AI on a mistake it made. The expletives that would occasionally follow would make sailor blush; or make you laugh maniacally depending on your breaking point.&lt;/p&gt;
&lt;h2&gt;Being Lazy&lt;/h2&gt;
&lt;p&gt;One day I was being lazy, as a good developer should be, and instead of writing a bit of code, I decided to ask ChatGPT to do a task. I had a UNIX timestamp and I wanted to know what the time and date it was generated.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/d33f4dfe-505d-4d89-8d9b-8e95f239006a/Screenshot%202025-07-05%20103754.png&quot; alt=&quot;Ask ChatGPT to convert a UNIX timestamp&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Excellent, its recognised it as a UNIX timestamp and seems to know what to do, and look it has even converted it from UTC to local time. Nice...&lt;/p&gt;
&lt;p&gt;Hang on a minute, something is not quite right. Today is Wednesday, 11th June 2025 (Australia) yet the response says the date was generated on a Saturday the 10th.&lt;/p&gt;
&lt;p&gt;Let&#39;s see if we can get the AI to correct its mistake.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/0a1ea589-8f42-472c-a847-dd22cc474781/Screenshot%202025-07-05%20104906.png&quot; alt=&quot;Asking ChatGPT to correct its mistake&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Okay that seems better but now I am nervous so I go `old skool` and actually write some code&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1749633533666&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the answer&lt;/p&gt;
&lt;pre class=&quot;language-jsonc&quot;&gt;&lt;code class=&quot;language-jsonc&quot;&gt;Wed Jun 11 2025 19:18:53 GMT+1000 (Australian Eastern Standard Time)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So even when corrected ChatGPT is still 2+ hours out. Sigh! But what is worrying is that if it had given this answer from the off I probably wouldn&#39;t have caught the mistake and may be even relied on the answer for something else, compounding the issue.&lt;/p&gt;
&lt;h2&gt;Over confidence&lt;/h2&gt;
&lt;p&gt;But why does a modern AI give us wrong answers(*) even when it &amp;quot;knows&amp;quot; the correct answer when corrected? I don&#39;t know but I feel the problem isn&#39;t new, we were aware of these issues even back at university. The willingness of our networks to give an answer on incomplete data, was seen as both a strength and a weakness. We were advised at the time &amp;quot;We don&#39;t really know how they work, so please don&#39;t use them for safety critical control systems&amp;quot;. Looking for defects in production lines, yes. Control your nuclear power reactor, no.&lt;/p&gt;
&lt;p&gt;Here I&#39;d like to tell you a story that explains the post headline and the accompanying picture. 30 years ago my friend, was studying for his PhD and was using neural networks for images that had been pre-processed, edge detection etc. We knew of bias even then and so he was looking to remove anything from the image that was not the subject he wanted to detect. He decided to use toys as his subject, easy to manipulate, and he had a set of toy soldiers that he trained his network on and he also had a set of plastic animals. He used these items to train his networks, one for soldiers and one for animals.&lt;/p&gt;
&lt;p&gt;One day he was asked to demo his progress and so he loaded up a pre-trained model, inserted a toy soldier into the box and snap. The computer whirred, photo taken, image processed, data sent to the neural network on the transputer array and back came the answer, &amp;quot;Elephant&amp;quot;. Now this was funny to everyone, except possibly my friend, as it was so obvious he had loaded the wrong network. But it shows that the neural network was willing to give an answer even when it so obviously wrong to the rest of us. Of course if the network was big enough it could&#39;ve been trained on both sets of toys and then it would have some training on what a soldier is as well as what an elephant is and perhaps then would&#39;ve got the answer right. No matter how big a network or the number of subjects trained upon, I don&#39;t believe it would&#39;ve been able to respond with &amp;quot;I don&#39;t know&amp;quot; when presented with unknown data, the willingness to supply an answer is its goal.&lt;/p&gt;
&lt;p&gt;Now modern AIs are obviously much, much bigger and have been trained on nearly the total wealth of available human and now synthesized output(**) but using similar training principles. It needs to supply an answer, in fact that is the business model of many of these companies, no-one wants to spend a credit on asking a question and get a &amp;quot;I don&#39;t know&amp;quot; response. So in some respects we have asked for this situation we find our selves in.&lt;/p&gt;
&lt;p&gt;(*) I know the modern term is hallucinations but I feel this usage masks a serious problem with modern AIs and the trust we put in them.&lt;br /&gt;
(**) model collapse is a major concern for the future of AIs.&lt;/p&gt;
</description>
      <pubDate>Tue, 01 Jul 2025 09:04:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/this-is-an-elephant/</guid>
    </item>
    <item>
      <title>Upgrading yarn from 1.x</title>
      <link>https://blog.many-monkeys.com/posts/upgrading-yarn-from-1-x/</link>
      <description>&lt;p&gt;I needed to update a project from yarn 1.x to the latest version (and maintain node modules) and though I have done this a number of times this year I always look up the instructions from the &lt;a href=&quot;https://yarnpkg.com/migration/overview&quot;&gt;yarn website&lt;/a&gt;. Today I struggled to find them and then eventually realised that the instructions were on an &lt;a href=&quot;https://v3.yarnpkg.com/getting-started/migration&quot;&gt;older version&lt;/a&gt; of the yarn website (for 3.x) and that they were not included in the latest website (for 4.x).&lt;/p&gt;
&lt;p&gt;So for my own sanity I am noting them here [Note this works for 1.22.19 to 4.0.2]&lt;/p&gt;
&lt;pre class=&quot;language-cmd&quot;&gt;&lt;code class=&quot;language-cmd&quot;&gt;yarn set version berry    
yarn config set nodeLinker node-modules            
yarn install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then a little testing and deduping doesn&#39;t go amiss here&lt;/p&gt;
&lt;pre class=&quot;language-cmd&quot;&gt;&lt;code class=&quot;language-cmd&quot;&gt;yarn test
yarn dedupe
yarn test&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, add the following to &lt;code&gt;.gitignore&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-ascii&quot;&gt;&lt;code class=&quot;language-ascii&quot;&gt;.yarn/*
!.yarn/releases&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, if possible, add it to renovate (updating according the node version) so that deduping happens on every package update &lt;code&gt;&amp;quot;postUpdateOptions&amp;quot;: [&amp;quot;yarnDedupeHighest&amp;quot;],&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;&quot;$schema&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://docs.renovatebot.com/renovate-schema.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;&quot;extends&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;config:base&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;&quot;automerge&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;&quot;labels&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;renovate&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;&quot;timezone&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Australia/Melbourne&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;&quot;postUpdateOptions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;yarnDedupeHighest&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;&quot;packageRules&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;&quot;matchUpdateTypes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;minor&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;patch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;digest&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;&quot;matchPackagePatterns&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;&quot;automerge&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;&quot;matchPackagePatterns&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;&quot;allowedVersions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;= 18&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once everything is stable and patched/upgraded then I look if it is possible to switch to yarn with PnP.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@itfeelslikefilm?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;🇸🇮 Janko Ferlič&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/photography-of-white-treadle-on-brown-wooden-rack-eBtwD6ZG78I?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Sun, 17 Dec 2023 23:20:01 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/upgrading-yarn-from-1-x/</guid>
    </item>
    <item>
      <title>CSP and Alpine.js</title>
      <link>https://blog.many-monkeys.com/posts/csp-and-alpine-js/</link>
      <description>&lt;p&gt;Whilst attempting to convert my blog to use a Content Security Policy (CSP) I was inundated with CSP violations relating to &lt;code&gt;unsafe-eval&lt;/code&gt; that was nailed down to the use of the &lt;a href=&quot;https://alpinejs.dev/&quot;&gt;alpine.js&lt;/a&gt; package. Now Alpine.js does have a &lt;a href=&quot;https://alpinejs.dev/advanced/csp&quot;&gt;CSP friendly&lt;/a&gt; build but it is yet (at the time of writing) to be published to &lt;a href=&quot;http://npmjs.com/&quot;&gt;npm&lt;/a&gt;. The instructions require you to build and distribute your own copy of alpine.js which isn&#39;t ideal but once that hurdle has been overcome it is possible to convert our usage to be CSP friendly. The instructions on alpine.js are rather light in detail about what this entails and so I will detail some of my own findings.&lt;/p&gt;
&lt;h2&gt;Starting off&lt;/h2&gt;
&lt;p&gt;The navbar for this site is one of the controls utilising alpine.js and this is what it looked like before conversion.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nav&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;x-data&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{ isOpen: false }&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;@keydown.escape&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;isOpen = false&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;@click.away&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;isOpen = false&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!--Toggle button (hidden on large screens)--&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;@click&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;isOpen = !isOpen&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;:class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{ &#39;transition transform-180&#39;: isOpen }&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Menu&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;h-6 w-6 fill-current&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;viewbox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 24 24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;x-show&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;isOpen&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;fill-rule&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;evenodd&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;clip-rule&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;evenodd&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;x-show&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;!isOpen&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;fill-rule&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;evenodd&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...  
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Identification of the &lt;code&gt;unsafe-inline&lt;/code&gt; violations&lt;/h2&gt;
&lt;p&gt;The following items cause the &lt;code&gt;unsafe-inline&lt;/code&gt; violation to fire and will need moving to external APIs as detailed by alpine.js&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;{ isOpen: false }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!isOpen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isOpen = false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isOpen = !isOpen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{ &#39;transition transform-180&#39;: isOpen }&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Creating and applying the external API&lt;/h2&gt;
&lt;p&gt;Following the initial advice and some investigation (okay some judicious logging) the following API was created&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;Alpine&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;navbar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;isOpen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;isClosed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;closeNavbar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;toggleNavbar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;generateNavbarClasses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;transform-180&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and wired into the html like so&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nav&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;x-data&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;navbar&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;@keydown.escape&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;closeNavbar&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;@click.away&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;closeNavbar&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!--Toggle button (hidden on large screens)--&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;@click&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;toggleNavbar&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;:class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;generateNavbarClasses&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Menu&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;h-6 w-6 fill-current&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;viewbox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 24 24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;x-show&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;isOpen&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;fill-rule&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;evenodd&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;clip-rule&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;evenodd&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;x-show&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;isClosed&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;fill-rule&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;evenodd&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repeating the above steps for other areas now means the site is CSP friendly and &lt;code&gt;unsafe-eval&lt;/code&gt; does not need to be applied to the Content Security Policy for the site to work.&lt;/p&gt;
&lt;p&gt;As always, your feedback is appreciated&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@stywo?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Stephan Seeber&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/white-and-black-snow-cap-mountain-under-cloudy-sky-4ZPmkBGE3Fo?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Sun, 22 Oct 2023 08:54:54 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/csp-and-alpine-js/</guid>
    </item>
    <item>
      <title>Protecting me from myself</title>
      <link>https://blog.many-monkeys.com/posts/protecting-me-from-myself/</link>
      <description>&lt;p&gt;I&#39;ve mentioned in the past that I use &lt;a href=&quot;https://blog.many-monkeys.com/posts/simplifying-your-package-management-and-security/&quot;&gt;renovate and dependabot&lt;/a&gt; to manage package updates for my repositories but sometimes though the build is good, the package update breaks my local development environment or doesn&#39;t follow my preferred practice. Since we get 2000 GitHub Action minutes for free on a personal account (and I have paid for minutes on some of my organisation accounts) I decide to use some of them for these sanity checks.&lt;/p&gt;
&lt;h2&gt;Yarn Package Deduplication&lt;/h2&gt;
&lt;p&gt;I have a preference to dedupe my packages and ensure that I have the highest version of each package that is possible. I do this so that when I am taking security updates I have found it is quicker to adopt these updates when my packages are already deduplicated. Usually renovate does a good job of deduplication (dependabot less so) but occasionally it doesn&#39;t dedupe the packages and I have to do this manually, but only if I know/recognise that this is required. Yarn v3 has a command for this &lt;code&gt;yarn dedupe&lt;/code&gt; (for Yarn v1 I use the &lt;a href=&quot;https://www.npmjs.com/package/yarn-deduplicate&quot;&gt;yarn-deduplicate&lt;/a&gt; package).&lt;/p&gt;
&lt;p&gt;The GitHub Action for this looks like this&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;yarn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; check yarn
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v4
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Setup Nodejs
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@v3
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 18.x
          &lt;span class=&quot;token key atrule&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn install &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;immutable
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn dedupe &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;check&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this action I can ensure that the &lt;code&gt;package.json&lt;/code&gt; and the &lt;code&gt;yarn.lock&lt;/code&gt; file are in sync and that there are no packages that can be deduped.&lt;/p&gt;
&lt;h2&gt;Validate .tool-versions&lt;/h2&gt;
&lt;p&gt;Just recently I took a renovate update that was to upgrade to the latest version of node 18 and as part of the that update it updated my &lt;code&gt;.tool-versions&lt;/code&gt;. However the version of node being upgraded to wasn&#39;t yet available via the &lt;a href=&quot;https://asdf-vm.com/&quot;&gt;asdf&lt;/a&gt; tooling; the irony of this update breaking my developer experience is not lost on me. Whilst researching how to build my own step/action to install asdf and then install the tools to check their availability, I lucked upon an &lt;a href=&quot;https://github.com/asdf-vm/actions&quot;&gt;action&lt;/a&gt; that already does what I needed and so I plugged that in.&lt;/p&gt;
&lt;p&gt;The GitHub Action for this looks something like this&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;asdf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; check asdf
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v4
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install asdf &amp;amp; tools
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; asdf&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;vm/actions/install@v3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once these sanity check steps are wired into the branch any failures of these steps will highlight in the PR and in the case of renovate stop any auto merges that have broken the build.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/950a99c0-7be2-4088-aaed-d67396110cff/Screenshot%202023-10-15%20180217.png&quot; alt=&quot;Adding GitHub Actions to branch protection &quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/9e6cfc5a-6d46-4457-8042-beda493564c1/Screenshot%202023-10-15%20180833.png&quot; alt=&quot;GitHub Actions failing the build&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Though, I have shown the jobs as separate actions for the above examples it is more efficient (reduced GitHub Action minutes) to merge them together and run them as one.&lt;/p&gt;
&lt;p&gt;As always, your feedback is welcomed and appreciated.&lt;/p&gt;
&lt;p&gt;Photo by&lt;a href=&quot;https://unsplash.com/@bernardhermant?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt; Bernard Hermant&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/IhcSHrZXFs4?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Sat, 14 Oct 2023 22:31:05 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/protecting-me-from-myself/</guid>
    </item>
    <item>
      <title>Lambda function not picking up new configuration</title>
      <link>https://blog.many-monkeys.com/posts/lambda-function-not-not-picking-up-new-configuration/</link>
      <description>&lt;p&gt;&lt;img src=&quot;https://blog.many-monkeys.com/posts/lambda-function-not-not-picking-up-new-configuration/&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The other day we encountered a very unusual scenario with one of our production systems, that even after many years of working with AWS Lambdas took us by surprise; well at least me.&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;We updated the environment variables of a number of Lambdas in our stack due to a deprecation of systems that now had newer replacements. We were really proud with ourselves that we had done this well in advance of the old systems being switched off and the platform worked as expected with the new configuration; we patted ourselves on the back and moved on. Then the legacy system was switched off and one (of many) Lambdas started to bleat. Looking at the logs we could see it was still trying to talk to the old system and yet we could see the new configuration for that Lambda in the AWS Console.
What was going on!?&lt;/p&gt;
&lt;h2&gt;Investigation&lt;/h2&gt;
&lt;p&gt;As mentioned we could see the new configuration in the AWS Console and yet the Lambda was still using the older configuration. We did the usual knee-jerk actions such as force a redeploy; we weren&#39;t hopeful as the Application stack that this Lambda belongs to is often deployed several times a week due to npm and terraform module updates, but hey it is worth a try. We could see the the new stack was deployed as one of our environment variables was the latest build number and that had changed and yet the important environment variable to direct to the new infrastructure was still not being picked up. A review of the code also led to more head scratching as the Lambda was actually very trivial; validate some incoming data and ping the newer service with the result, it used only a couple of libraries for logging purposes so it should really be idiot proof. If any Lambda in this stack was going to cause us issues this one was at the bottom of the list.&lt;/p&gt;
&lt;p&gt;It turns out that simplicity of the lambda was its downfall. Despite all the deploys of the stack the generated output code of that particular Lambda never actually changed i.e. the JavaScript was identical and had remained the same for at least the past month. It would appear that a physical difference of uploaded code is needed for a Lambda to pick up the new configuration from the environment variables. So a small tweak to the code, an extra logging line, and after the next deploy we could see the new config was now being used. Crisis averted!&lt;/p&gt;
&lt;h2&gt;Solution/Workaround&lt;/h2&gt;
&lt;p&gt;So that we don&#39;t run into this situation again, what we need to do was make sure the code changes on every deploy and thus force a refresh of the configuration via the supplied environment variables [these aren&#39;t secrets by the way]. We initially thought about generating a file with a build number or date and then pulling that in to each lambda but that felt messy. So then our thoughts turned to our build system and we identified a webpack plugin called &lt;a href=&quot;https://webpack.js.org/plugins/banner-plugin/&quot;&gt;&lt;code&gt;BannerPlugin&lt;/code&gt;&lt;/a&gt; that can be used to inject snippets into the header or footer of the output file i.e. our Lambda code. What we ended up doing was something like the following in our webpack configuration:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; BannerPlugin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Configuration &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;webpack&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; buildNumber &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;BUILD_NUMBER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Configuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  plugins&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BannerPlugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      banner&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;var __build_number__ = &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;buildNumber&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      raw&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

modules&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, each Lambda we produce using this config is stamped with the build number and thus making each incarnation we deploy unique.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/c686d0f4-2eae-4a41-9318-06411ada22b4/-/crop/662x233/0,53/-/preview/269551737-42b819db-7362-42e2-8bef-abdae0f904a0.png&quot; alt=&quot;A code snippet from AWS console showing the inserted code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Note: If you don&#39;t have a build number to hand you could just use &lt;code&gt;Date.now()&lt;/code&gt; or some other mechanism to generate a unique enough value.&lt;/p&gt;
&lt;h2&gt;Feedback&lt;/h2&gt;
&lt;p&gt;As always, your thoughts are always appreciated.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@brett_jordan?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Brett Jordan&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/wvfbpzLbZVg?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Fri, 22 Sep 2023 11:31:09 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/lambda-function-not-not-picking-up-new-configuration/</guid>
    </item>
    <item>
      <title>Some notes on setting up a CSP on a legacy site</title>
      <link>https://blog.many-monkeys.com/posts/some-notes-on-setting-up-a-csp-on-a-legacy-site/</link>
      <description>&lt;h2&gt;Nonces instead of Hashes&lt;/h2&gt;
&lt;p&gt;Using hashes for small sites is okay when you have a small number of scripts and styles from internal and external sources but quickly becomes unwieldy when working with a large and the better approach is to use nonces. Since a nonce needs to be applied afresh each time a page is served then a placeholder is often used in your code and then replaced by server processing e.g.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;**CSP_NONCE_PLACEHOLDER**&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://xyz.com/script.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;**CSP_NONCE_PLACEHOLDER**&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;**CSP_NONCE_PLACEHOLDER**&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
  ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;NGINX&lt;/h3&gt;
&lt;p&gt;A lot of sites use nginx and it is simple to replace the placeholder using a sub filter&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set $cspNonce &amp;quot;${request_id}&amp;quot;;
sub_filter_once off;
sub_filter_types *;
sub_filter **CSP_NONCE_PLACEHOLDER** $cspNonce;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated nonce can then be used later on when creating the &lt;code&gt;Content-Security-Policy&lt;/code&gt; header.&lt;/p&gt;
&lt;h2&gt;Nonces and external ...&lt;/h2&gt;
&lt;h3&gt;... scripts&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;strict-dynamic&lt;/code&gt; keyword can be used with nonces to trust a script and simplify your CSP as you can ditch the domain whitelists (for &lt;code&gt;script-src&lt;/code&gt; only).&lt;/p&gt;
&lt;h3&gt;... code snippets&lt;/h3&gt;
&lt;p&gt;Over the years your legacy code base has probbaly acquired a lot of code snippets especially by tracking networks that are so useful to help you understand your users e.g. googletagmanager. At the time these scripts were pasted into your pages they were probably ignorant of nonces and so will stop working properly when they now try to create a &lt;code&gt;&amp;lt;script /&amp;gt;&lt;/code&gt; element. Since then google have created a nonce aware script that is &lt;a href=&quot;https://developers.google.com/tag-platform/security/guides/csp&quot;&gt;compatible&lt;/a&gt; with the latest CSP version. Comparing the scripts (old vs new) the following line of code was added, to get a nonce from the page and apply it to the &lt;code&gt;&amp;lt;script /&amp;gt;&lt;/code&gt; tag being created&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; n&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[nonce]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
n&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;nonce&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nonce&lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;nonce&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now a lot of these type of scripts (same era) use the same pattern/technique to inject a &lt;code&gt;&amp;lt;script /&amp;gt;&lt;/code&gt; block onto your page and it is possible to tweak the above line for each scenario.&lt;/p&gt;
&lt;p&gt;Note: This may be less of an issue nowadays due to cookie consent policies as these snippets are often refactored out to loaded only when the site visitor has consented to their use.&lt;/p&gt;
&lt;h2&gt;Inline scripts&lt;/h2&gt;
&lt;p&gt;It is common to execute JavaScript code on user actions e.g.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;select&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;onchange&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value javascript language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To avoid supplying hashes for every snippet they can be refactored to use an inline script i.e.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;select&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;picker&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;**CSP_NONCE_PLACEHOLDER**&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;picker&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;change&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;JavaScript URLs&lt;/h3&gt;
&lt;p&gt;Using a JavaScript URL on the &lt;code&gt;href&lt;/code&gt; of an anchor (&lt;code&gt;&amp;lt;a /&amp;gt;&lt;/code&gt;) tag was often used to emulate a button but without all the default styling that came with a button and then using a library like JQuery to attach the proper event handler e.g.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;clickme&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;javascript:void(0);&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Click Me!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The recommendation is to convert them into &lt;code&gt;button&lt;/code&gt; elements and attach the event via an event listener (as above) which is also better IMO for accessibility. If there are 100s (or 1000s) of these then this might be a mammoth task and so the first instinct maybe  to use a hash of the script i.e.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&#39;sha256&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;rRMdkshZyJlCmDX27XnL7g3zXaxv7ei6Sg+yt4R3svU=&#39; &lt;span class=&quot;token comment&quot;&gt;# javascript:void(0)&lt;/span&gt;
&#39;sha256&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;kbHtQyYDQKz4SWMQ8OHVol3EC0t3tHEJFPCSwNG9NxQ=&#39; &lt;span class=&quot;token comment&quot;&gt;# javascript:void(0);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there are &lt;a href=&quot;https://blog.many-monkeys.com/posts/some-notes-on-setting-up-a-csp-on-a-legacy-site/sha256-rRMdkshZyJlCmDX27XnL7g3zXaxv7ei6Sg+yt4R3svU=&quot;&gt;articles&lt;/a&gt; that indicated that this is (or was) possible but browser compatibility isn&#39;t comprehensive. Alternatives such as using &lt;code&gt;href=&amp;quot;#!&amp;quot;&lt;/code&gt; may work better.&lt;/p&gt;
&lt;p&gt;I&#39;ve personally found that replacing the &lt;code&gt;href&lt;/code&gt; attribute with a &lt;code&gt;role&lt;/code&gt; with appropriate styling is cleaner and also improves accessibility e.g.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;clickme&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;btn&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Click Me!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What else?&lt;/h2&gt;
&lt;p&gt;More to be added as and when...&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@freegraphictoday?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;AbsolutVision&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/82TpEld0_e4?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Sat, 02 Sep 2023 10:08:15 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/some-notes-on-setting-up-a-csp-on-a-legacy-site/</guid>
    </item>
    <item>
      <title>Steps to setting up a Content Security Policy</title>
      <link>https://blog.many-monkeys.com/posts/steps-to-setting-up-a-content-security-policy-for-your-site/</link>
      <description>&lt;p&gt;As part of protecting your site and your users you should really consider applying a Content Security Policy (CSP) to your site. I am going to describe the path I took to applying a basic CSP to my blog and the tools I used to make my journey less painful.&lt;/p&gt;
&lt;p&gt;But first what is a CSP and why should you care?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&quot;&gt;Content Security Policy (CSP)&lt;/a&gt; is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft, to site defacement, to malware distribution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;quot;But I am already using the &lt;code&gt;X-Frame-Options&lt;/code&gt; and &lt;code&gt;X-XSS-Protection&lt;/code&gt; headers so I am protected right?&amp;quot; Probably not any more, modern browsers have &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection#browser_compatibility&quot;&gt;dropped&lt;/a&gt; support for &lt;code&gt;X-XSS-Protection&lt;/code&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options#browser_compatibility&quot;&gt;deprecated&lt;/a&gt; some of the capabilities of &lt;code&gt;X-Frame-Options&lt;/code&gt; in favour of a CSP being supplied instead. A CSP is however extremely configurable/flexible and with that comes additional complexity. To help with that there are two headers that we need to be aware of when writing a CSP.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Content-Security-Policy - this is the header we will eventually be using to enforce the policy&lt;/li&gt;
&lt;li&gt;Content-Security-Policy-Report-Only - this is the header we will start with, this header checks the policy but does not enforce it, allowing corrections to be made until all issues are rectified.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both headers will generate messages in the console (Chrome at least) and through the use of the &lt;code&gt;report-uri&lt;/code&gt; or &lt;code&gt;report-to&lt;/code&gt; directives can send those reports to a 3rd party reporting service.&lt;/p&gt;
&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;To start building a CSP for a site we can start with a basic reporting header&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content-Security-Policy-Report-Only: &amp;quot;default-src &#39;none&#39;;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The directive &lt;code&gt;default-src&lt;/code&gt; is the final fallback for all of the other directives that are available in a CSP header, by setting it to &lt;code&gt;none&lt;/code&gt; will force every possible violation to be reported and will allow full visibility of what interactions the site actually has.&lt;/p&gt;
&lt;p&gt;Once the basic header has been applied, a refresh of the site will produce a very noisy report.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/05a8da9d-70f8-4442-879c-60b9a9256fcb/-/crop/983x1077/0,0/-/preview/Screenshot%202023-08-05%20170945.png&quot; alt=&quot;Example CSP reporting from Chrome&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The number of reported violations may look daunting at first but they can be easily reduced by applying directives that refer to interactions reported.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is not unusual to see &lt;code&gt;default-src&lt;/code&gt; set to &lt;code&gt;self&lt;/code&gt; rather than &lt;code&gt;none&lt;/code&gt; as this can quickly cut the noise with little effort but it will also hide interactions that you may be unaware of; depending on the security posture of a site this may be okay.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Reducing the noise&lt;/h2&gt;
&lt;p&gt;Rather than set &lt;code&gt;default-src&lt;/code&gt; to &lt;code&gt;self&lt;/code&gt;, it is sometimes better for visibility to apply the &lt;code&gt;self&lt;/code&gt; option to each of the applicable directives. Doing so will allow the browser to trust the host site for each of the interactions reported; in this case the browser will trust images (PNG, GIF, ...), js (JavaScript) and css (Style sheets) from the host site.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content-Security-Policy-Report-Only: &amp;quot;default-src &#39;none&#39;; 
  img-src &#39;self&#39;; script-src-elem &#39;self&#39;; style-src-elem &#39;self&#39;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/b8cc62d3-81c6-42c1-ae92-19e03389653e/Screenshot%202023-08-05%20200759.png&quot; alt=&quot;A CSP report from Chrome with reduced noise&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now that the &lt;code&gt;self&lt;/code&gt; interactions have been dealt with it is now possible to deal with the violations relating to external interactions&lt;/p&gt;
&lt;p&gt;This now becomes an iterative process of updating the CSP, applying it and reviewing the results. The report will inform as to which directive is being violated and possible remediation steps.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content-Security-Policy-Report-Only: &amp;quot;default-src &#39;none&#39;; img-src &#39;self&#39;; 
  script-src-elem &#39;self&#39; cdn.jsdelivr.net netlify-cdp-loader.netlify.app unpkg.com; 
  style-src-elem &#39;self&#39; cdn.jsdelivr.net; frame-src app.netlify.com&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/3073dcd4-ac6c-4f4d-a6da-081a73aaac27/Screenshot%202023-08-05%20203105.png&quot; alt=&quot;Another CSP report from Chrome with reduced noise&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Unsafe?&lt;/h2&gt;
&lt;p&gt;Now the only violations being reported are suggesting the &lt;code&gt;unsafe-*&lt;/code&gt; keywords as possible solutions. Any use of these keywords should be a temporary measure and plans should be made to replace them with something more secure.&lt;/p&gt;
&lt;p&gt;There are several ways to deal with inline scripts and styles as suggested in the report. If there are just a few inline scripts and styles then using the suggested hashes is probably the quickest solution. This however can quickly become unwieldly and perhaps using a nonce is much better, this approach will require some sort of backend processing to ensure nonce(s) are generated and applied on each page impression. For modern static sites without a backend server available to generate a nonce, then extracting these scripts and styles into separate files is probably the better approach.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content-Security-Policy-Report-Only: &amp;quot;default-src &#39;none&#39;; img-src &#39;self&#39;; 
  script-src-elem &#39;self&#39; &#39;sha256-bX5JSFYfDe6u21arSDQFhDhQZCpkhyBKkXyrQB1U2rM=&#39;
    cdn.jsdelivr.net netlify-cdp-loader.netlify.app unpkg.com; 
  script-src &#39;unsafe-eval&#39;; style-src-elem &#39;self&#39; cdn.jsdelivr.net; 
  style-src &#39;unsafe-hashes&#39; &#39;sha256-dH+oOZOdDv+MWU0F8bCZOoFHX0jFM4+bwNqOKujbv90=&#39;; 
  frame-src app.netlify.com&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Leading to no violation reports being generated. This is just one page and more updates to the CSP will be required as the rest of the site is tested against the applied policy.&lt;/p&gt;
&lt;p&gt;Using hashes or nonces is recommended but if the violations are coming from 3rd party scripts then they are much harder to control especially if the styles or scripts are changing regularly. It is not surprising developers get frustrated and resort to just using the &lt;code&gt;unsafe-*&lt;/code&gt; keywords and move on.&lt;/p&gt;
&lt;p&gt;It is also possible to use the &lt;code&gt;strict-dynamic&lt;/code&gt; keyword against the &lt;code&gt;script-src&lt;/code&gt; directive, this will usually reduce the number of hashes to be applied against the &lt;code&gt;script-src-elem&lt;/code&gt; directive. Unfortunately there does not seem to be an equivalent for &lt;code&gt;style-src&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note: With browsers that support CSP-2 then &lt;code&gt;unsafe-inline&lt;/code&gt; is ignored if a hash or nonce is provided for that directive but it will still allow the site to work with older browsers that only support CSP-1.&lt;/p&gt;
&lt;h2&gt;Moving from reporting to enforcement&lt;/h2&gt;
&lt;p&gt;After a number of iterations no more violations should be recorded and the next step is to move to enforcement, but what happens if something is missed and something breaks for visitors to the site. As mentioned earlier there are two reporting directives that can be used to send violation reports to a reporting endpoint. You could create your own if you like but if you needs are light then a 3rd party service will probably suffice.&lt;/p&gt;
&lt;h3&gt;3rd party services&lt;/h3&gt;
&lt;p&gt;There are many providers to choose from and all offer similar services and capabilities. Adding a reporting endpoint to use one of these providers is as simple and only requires the use of the &lt;code&gt;report-to&lt;/code&gt; or &lt;code&gt;report-uri&lt;/code&gt; directives. The &lt;code&gt;report-uri&lt;/code&gt; directive, though being deprecated, is still the easiest to configure; if you decide to use this then keep an eye on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri#browser_compatibility&quot;&gt;browser support&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content-Security-Policy-Report-Only: &amp;quot;...; report-uri &amp;lt;uri-to-service&amp;gt; ;...&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are a couple of suggestions:&lt;/p&gt;
&lt;h3&gt;Report URI&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://report-uri.com/&quot;&gt;Report URI&lt;/a&gt; has a free offering that will suffice for a single site and get access to the basic reporting features. If a violation is reported it will be viewable hopefully enough information exists in the report to rectify the issue.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/2e47fc09-e146-4453-9578-16a64d2ac391/Screenshot%202023-08-06%20080949.png&quot; alt=&quot;A CSP report from Report URI&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There is also a wizard capability where the reporting can be used to dynamically build a CSP. It should be noted that, under the free version at least, that the CSP generated default to using &lt;code&gt;unsafe-*&lt;/code&gt; keywords rather than gather the hashes as we see in the console. This is because the hashes are not sent as part of the report.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/d50c7572-aa91-43d9-8e00-9b71692e178a/Screenshot%202023-08-06%20083635.png&quot; alt=&quot;A CSP report but no hash&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The hash however is generated by Chrome in the console&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/6784c6d4-9724-4185-b334-bc0f2bd8d4a3/Screenshot%202023-08-06%20084004.png&quot; alt=&quot;A violation report in Chrome with a hash&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Using hashes or nonces is recommended but if the violations are coming from 3rd party scripts then they are much harder to control especially if the styles or scripts are changing regularly. It is not surprising developers get frustrated and resort to using the &lt;code&gt;unsafe-*&lt;/code&gt; keywords alone and move on.&lt;/p&gt;
&lt;h3&gt;Csper&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://csper.io/&quot;&gt;Csper&lt;/a&gt; is another service that provides a reporting endpoint that you can use to collate reports. It doesn&#39;t, at this point, have a free offering but it does have a trial that may be worth investigating. It does however have a free Chrome extension that when loaded will gather the reports and then build a basic policy.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/f9c509eb-b19b-4f5c-861d-dbce324b2132/Screenshot%202023-08-06%20121058.png&quot; alt=&quot;A CSP generated by a chrome extension&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It is noted they do not grab/generate the hashes but instead suggest that any inline scripts and styles are rewritten instead; this is not bad advice but not something that can be extended to any 3rd party scripts.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/3d2291b7-7d5d-4530-9a98-3b3696955a61/Screenshot%202023-08-06%20121501.png&quot; alt=&quot;Suggested inline rewrites from the Chrome extension&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The extension is useful to create a basic policy but will need tweaking before it can be used in production.&lt;/p&gt;
&lt;h3&gt;CSP Evaluator&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://csp-evaluator.withgoogle.com/&quot;&gt;CSP Evaluator&lt;/a&gt; is a handy tool that will analyse your &lt;code&gt;Content-Security-Poilicy&lt;/code&gt; headers and check for any issues. It will provide suggestions on making your policy backward compatible for browsers that do not support the latest CSP syntax. There is also a Chrome extension that will check the policy on the current site but does not seem to, as yet, offer the backward compatibility suggestions.&lt;/p&gt;
&lt;h3&gt;Ready to go live?&lt;/h3&gt;
&lt;p&gt;Once the reports stop being generated and no more violations are being captured, it should be possible to switch the policy from reporting only to enforcement by changing the header from &lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; to &lt;code&gt;Content-Security-Policy&lt;/code&gt;. Now any violations from this point may cause site failures i.e. scripts will not run or styles may not be applied when expected. If you have a reporting endpoint then review any violations and decide, after repeating of course, if and how they need to be addressed.&lt;/p&gt;
&lt;h2&gt;Enough about XSS what about clickjacking?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;X-Frame-Options&lt;/code&gt; is still the old faithful if you want to prevent your site being wrapped in an IFRAME element but if you would like your site to be wrapped but control who is allowed to do so then you should extend the CSP.&lt;/p&gt;
&lt;p&gt;The CSP equivalent of &lt;code&gt;X-Frame-Options&lt;/code&gt; is the &lt;code&gt;frame-ancestors&lt;/code&gt; directive e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content-Security-Policy: &amp;quot;...; frame-ancestors &#39;self&#39; ;...&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Afterthought&lt;/h2&gt;
&lt;p&gt;I believe one of my first attempts at XSS was when I got involved in the &#39;Bearding Bob&#39; competition in 2002 on the Code Project website. To my total surprise I &lt;a href=&quot;https://www.codeproject.com/Members/shog9?msg=446302#xx446302xx&quot;&gt;won&lt;/a&gt;, though not sure if it was for my code or my graphic skills; probably not the latter and not convinced about the former either so probably just that I read and &lt;a href=&quot;https://www.codeproject.com/Members/shog9?msg=375165#xx375165xx&quot;&gt;followed the rules&lt;/a&gt;. The picture of the prize seems to have gone from the site but I still have it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/853f9b29-9380-4bb7-ad38-fc60d426d494/20230806_054043.jpg&quot; alt=&quot;Tankard with a bearded Bob image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As always, your feedback is welcome and appreciated.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sebastiaanstam?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;sebastiaan stam&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/RChZT-JlI9g?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Sat, 05 Aug 2023 05:11:20 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/steps-to-setting-up-a-content-security-policy-for-your-site/</guid>
    </item>
    <item>
      <title>Heroku wants paying, so time to move on...</title>
      <link>https://blog.many-monkeys.com/posts/heroku-wants-paying-so-time-to-move-on/</link>
      <description>&lt;p&gt;F﻿or over ten years I have been using &lt;a href=&quot;https://heroku.com/&quot;&gt;Heroku&lt;/a&gt; to host small servers using their free dyno offering, I have even hosted production servers on their platform because it was so easy to setup and manage. However, Since their &lt;a href=&quot;https://devcenter.heroku.com/changelog-items/2461&quot;&gt;announcement&lt;/a&gt; to cease their support of free dynos I have to find a new home for my blog, or more specifically the headless &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost&lt;/a&gt; CMS portion.&lt;/p&gt;
&lt;p&gt;Even though the end date isn&#39;t for another month or so, I find myself quite time poor and so I needed to move quickly. I realised there are a &lt;strong&gt;LOT&lt;/strong&gt; of blog hosting offerings and the choice is just bewildering; I also considered &lt;a href=&quot;https://medium.com/&quot;&gt;Medium&lt;/a&gt;, as I read it a lot and have a subscription, but couldn&#39;t find a way to host legacy posts.&lt;/p&gt;
&lt;p&gt;I needed a something simple, easy to migrate to, definitely easy to migrate from, and I that could host on my own domain. I already use &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; to host my &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt; generated blog and so I initially looked for solutions that would allow migration from one headless CMS to another but use the same site generator. I then realised that Netlify have their own &lt;a href=&quot;https://www.netlifycms.org/&quot;&gt;CMS&lt;/a&gt; so I decided to give that a look.&lt;/p&gt;
&lt;p&gt;A nice thing about Netlify CMS is that the blog content itself is hosted on your own Github account so you always have full control of the data. I also found that the local development experience was excellent in that I could tweak the articles as I migrated them across and instantly review them without having to go through a long build cycle and use up those precious Netlify build minutes.&lt;/p&gt;
&lt;h2&gt;Migration process&lt;/h2&gt;
&lt;p&gt;I don&#39;t intend to supply the scripts I used as they are a mess, I went fast and dirty here as I knew I would not need these scripts once the job is done. I will however talk about the tooling I used to migrate the data.&lt;/p&gt;
&lt;p&gt;First up was to migrate the blog data itself. Ghost CMS has an api and so using the &lt;a href=&quot;https://www.npmjs.com/package/@tryghost/content-api&quot;&gt;&lt;code&gt;@tryghost/content-api&lt;/code&gt;&lt;/a&gt; package I was able to quickly grab the content.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ghostContentAPI &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@tryghost/content-api&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; api &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ghostContentAPI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ghostURL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;xxxxxxxxxxxxxxxxxxxxxxxxxx&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;v2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; posts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; contentType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;browse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;tags,authors&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;all&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The content provided however was HTML and the Netlify CMS, as do a few others, requires it in &lt;a href=&quot;https://www.markdownguide.org/&quot;&gt;Markdown&lt;/a&gt; format instead.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/5251f755-41c6-49ce-b7bc-14faaa548ebe/Screen.png&quot; alt=&quot;a snippet of html downloaded from ghost cms&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To convert this to Markdown, I turned to another package &lt;a href=&quot;https://www.npmjs.com/package/turndown&quot;&gt;&lt;code&gt;turndown&lt;/code&gt;&lt;/a&gt; to do the conversion. Off the bat, it did a reasonable job but it failed to correctly handle code snippets that were using &lt;a href=&quot;https://prismjs.com/&quot;&gt;prismjs&lt;/a&gt;. What was needed was to extend turndown using a new rule to recognise these snippets and convert them correctly.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; TurndownService &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;turndown&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; turndownService &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TurndownService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
turndownService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addRule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;prismCode&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nodeName &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;PRE&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;childNodes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;childNodes&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nodeName &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;CODE&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^language-&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;childNodes&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;class&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;replacement&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; node&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; matches &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;childNodes&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;class&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^language-(?&amp;lt;lang&gt;.+)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;```&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
      matches&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;groups&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lang&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cmd&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;bash&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;,line-numbers&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
      content &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&#39;&#92;n```&#39;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; markdown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;html
    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; turndownService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;turndown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;html&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the posts now converted to markdown it is now possible to generate the post markdown files and map the data to the format expected by the Netlify CMS; the required content for a blog post is customisable and I suggest you give this some thought before committing the next step.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; template &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
---
date: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;published_at&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
title: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
description: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;custom_excerpt &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;custom_excerpt &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
featuredImage:
  src: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feature_image &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;feature_image &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/static/img/not-found-image.jpg&#39;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
... more fields go here
---
&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;markdown&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I needed to move the images as they were hosted on &lt;a href=&quot;https://cloudinary.com/&quot;&gt;Cloudinary&lt;/a&gt; but the account was tied to the Heroku account and application which I intended to delete. I used regex to identify the images hosted on Cloudinary and saved the files to disk, and then used regex again to rewrite the new locations in the markdown files.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; fs &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;fs-extra&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; fetch &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;node-fetch&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;downloadImage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputPath &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;outputFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;outputPath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Site generation&lt;/h2&gt;
&lt;p&gt;I also decided to ditch Gatsby and give &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt; a try instead as it appears to be more lightweight; if it is a disaster then I can always try something else now that I have my content in a convenient format. I also decided to change my comment platform to &lt;a href=&quot;https://utteranc.es/&quot;&gt;utterences&lt;/a&gt; as it is another github based storage solution and so I have full control of the data there as well.&lt;/p&gt;
&lt;p&gt;Site generation is currently &amp;lt; 30s whereas with the Gatsby+Ghost setup this was 3-4 mins; this is important as previews (editorial workflow) use a branch and need building+deploying before they can be seen.&lt;/p&gt;
&lt;h2&gt;Afterthought&lt;/h2&gt;
&lt;p&gt;There is still some work to do, tags, search etc..., and I am not 100% convinced the Netlify CMS is the final solution as it has not seen a lot of love of late however I have my data in a format that should be easy to migrate if needs be.&lt;/p&gt;
&lt;p&gt;Your feedback, as always, is appreciated!&lt;/p&gt;
</description>
      <pubDate>Fri, 23 Sep 2022 11:03:57 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/heroku-wants-paying-so-time-to-move-on/</guid>
    </item>
    <item>
      <title>Simplifying your package management and security</title>
      <link>https://blog.many-monkeys.com/posts/simplifying-your-package-management-and-security/</link>
      <description>&lt;p&gt;Every day seems to come with more package updates and security fixes and though I, like most I feel, tend to ignore them for personal projects, I do tend to keep an eye on those projects that are actively hosted/published eg my blog.&lt;/p&gt;
&lt;p&gt;But how do you stop it becoming a full time job? I used to heavily rely on Github&#39;s &lt;a href=&quot;https://github.com/dependabot&quot;&gt;dependabot&lt;/a&gt; but I was getting messages for upgrading almost daily; never mind the regular security patches and evaluating if they actually impacted my site.&lt;/p&gt;
&lt;p&gt;I then came across &lt;a href=&quot;https://www.mend.io/free-developer-tools/renovate/&quot;&gt;Renovate&lt;/a&gt; by Mend (was Whitespace) and realised that this was the path to take if I wanted to get some balance to my life. Setup was simple and I can control which projects renovate was allowed to manage. Once connected, Renovate will create a PR which tells you what it intends to do&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/8365dcda-124b-478b-bb20-55b6a8543024/renovate-first-pr.png&quot; alt=&quot;a list of actions provided by renovate&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once accepted, Renovate will then create a simple dashboard within your repository&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/a607d971-0d64-46e6-9884-78971ae84510/renovate-dashboard.png&quot; alt=&quot;a simple dashboard to manage renovate&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now the best bit of renovate, the configuration to save you time. If you have plenty of tests and are happy to release if your build+tests pass then you can automate the package management to merge them straight in. You can group &lt;code&gt;like&lt;/code&gt; packages together that always update around the same time eg jest or eslint, and for noisy packages, I am looking at you &lt;a href=&quot;https://www.npmjs.com/package/aws-sdk&quot;&gt;aws-sdk&lt;/a&gt;, that seem to update almost daily you can schedule/limit them to just once a week.&lt;/p&gt;
&lt;p&gt;I am still not 100% all-in on full automation but I have decided to allow minor-like patches on my devDependancies to be fully automated&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;$schema&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://docs.renovatebot.com/renovate-schema.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ...
  &lt;span class=&quot;token property&quot;&gt;&quot;packageRules&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    ...&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;matchUpdateTypes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;minor&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;patch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;digest&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;matchPackagePatterns&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;matchDepTypes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;automerge&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;automergeType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;branch&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now all I need to do is manage the major updates and check on packages that make up the production deliverables.&lt;/p&gt;
&lt;h2&gt;Extending renovate&lt;/h2&gt;
&lt;p&gt;Unlike dependabot, Renovate supports a lot more tools, eg Docker, BuildKite, ... to name but a few and will also accept extensions from contributors. You may have noticed the &lt;code&gt;.tool-versions (asdf)&lt;/code&gt; extension in the above images, I am glad to say that I was &lt;a href=&quot;https://github.com/renovatebot/renovate/tree/main/lib/modules/manager/asdf&quot;&gt;involved&lt;/a&gt; in writing that extension and though it only supports &lt;code&gt;nodejs&lt;/code&gt; for now it should be easy for others to extend for their asdf managed tooling should they need to; I may update it myself but I only intend to do so for tools I need.&lt;/p&gt;
&lt;h2&gt;Security alerts&lt;/h2&gt;
&lt;p&gt;Though Mend does have a security module it is not something as a home developer I could afford so I still use dependabot to provide security alerts but as I am more on top of package updates I have found these happening less frequently.&lt;/p&gt;
&lt;p&gt;Your feedback, as always, is appreciated.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@flyd2069?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;FLY:D&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/cyber-security?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Mon, 19 Sep 2022 08:24:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/simplifying-your-package-management-and-security/</guid>
    </item>
    <item>
      <title>Speed up your Docker developer experience on MacOS</title>
      <link>https://blog.many-monkeys.com/posts/speed-up-your-docker-developer-experience-on-macos/</link>
      <description>&lt;p&gt;Okay, if you are reading this, you probably already know that Docker (and not just Docker Desktop) on a MacOS can be awfully slow, especially for developers when the container is accessing files on the local drive via a volume mount. For the most part, this has not really been noticeable with the applications I develop against and so I have been happy to use the defaults. More recently though I have been working on a PHP application and due to its nature it required that &amp;quot;nearly&amp;quot; the whole development space needed to be mapped to a volume and the impact was very apparent even when using the &lt;a href=&quot;https://docs.docker.com/desktop/mac/&quot;&gt;gRPC FUSE option&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Starting point&lt;/h2&gt;
&lt;p&gt;Using a fairly standard delegated mapping like the one below, we found that the average time to open our home page locally was ~600ms (with the gRPC fuse setting)&lt;/p&gt;
&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;3.5&#39;&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/var/www/&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;delegated&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Though not the simplest page it wasn&#39;t the most complex we have to deal with, can we do better?&lt;/p&gt;
&lt;h2&gt;Using NFS Mounts&lt;/h2&gt;
&lt;p&gt;Now a common approach to addressing this issue has been to use an NFS mount instead, setting it up is quite complicated but thankfully it is well documented and scripts are &lt;a href=&quot;https://gist.github.com/sawilde/1f3e74b4c9c8837308b385e631cf064b&quot;&gt;readily available&lt;/a&gt; for us to use.&lt;/p&gt;
&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;3.5&#39;&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; nfsmount&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/var/www/

&lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;nfsmount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; local
&lt;span class=&quot;token key atrule&quot;&gt;driver_opts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nfs
  &lt;span class=&quot;token key atrule&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; addr=host.docker.internal&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;rw&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;nolock&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;hard&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;nointr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;nfsvers=3
  &lt;span class=&quot;token key atrule&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;:${PWD}&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Switching to the above config for mounting the file system and running the same home page test reduced our average load time to ~290ms.  This is a pretty good improvement but can we do better?&lt;/p&gt;
&lt;h2&gt;Using Mutagen&lt;/h2&gt;
&lt;p&gt;Mutagen is a file synchronization utility that can be used with containers and more recently, with the beta version at least, it can be configured using &lt;code&gt;docker-compose&lt;/code&gt; files.&lt;/p&gt;
&lt;h3&gt;Installing&lt;/h3&gt;
&lt;p&gt;Installing is quite easy, though it may take some time; there may be a faster approach but I just followed the hints from homebrew.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;xcode-select &lt;span class=&quot;token parameter variable&quot;&gt;--install&lt;/span&gt;
brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; mutagen-io/mutagen/mutagen-compose-beta
mutagen daemon start&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Configuring&lt;/h3&gt;
&lt;p&gt;Since we are using the beta we can define the mounts in our &lt;code&gt;docker-compose&lt;/code&gt; files.&lt;/p&gt;
&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;3.5&#39;&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/var/www/

&lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;x-mutagen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;ignore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;vcs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; .DS_Store
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; .git
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; .idea
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; .vscode
  &lt;span class=&quot;token key atrule&quot;&gt;permissions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;defaultFileMode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0644&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;defaultDirectoryMode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0755&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;volume://code&quot;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;two-way-resolved&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: the permissions section was required as mutagen applies the default permissions of 0600 and 0700 for files and directories respectively however I require the permissions to be 0644 and 0755 so that I could launch the web application (nginx).&lt;/p&gt;
&lt;p&gt;Finally, we need to use &lt;code&gt;mutagen-compose&lt;/code&gt; instead of &lt;code&gt;docker-compose&lt;/code&gt; on the command line (or in scripts). It takes a little longer to start due to the initial build of the docker volume; this can be tweaked by being more selective on what files need to be synchronized between the host and the docker volume.&lt;/p&gt;
&lt;p&gt;Running the same test again, against the home page, we managed to reduce the average load time to ~160ms.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;All of the above tests were done for a developer build, performance is much better for production builds which are hosted in the cloud.&lt;/p&gt;
&lt;p&gt;method&lt;/p&gt;
&lt;p&gt;load time (ms)&lt;/p&gt;
&lt;p&gt;default&lt;/p&gt;
&lt;p&gt;~600&lt;/p&gt;
&lt;p&gt;nfsmount&lt;/p&gt;
&lt;p&gt;~290&lt;/p&gt;
&lt;p&gt;mutagen&lt;/p&gt;
&lt;p&gt;~160&lt;/p&gt;
&lt;p&gt;It seems that mutagen is definitely a candidate to mitigate some of the performance issues encountered with Docker on the MacOS and should be considered alongside other utilities like &lt;a href=&quot;https://docker-sync.readthedocs.io/en/latest/getting-started/installation.html#installation-osx&quot;&gt;docker-sync&lt;/a&gt; (requires ruby) and &lt;a href=&quot;https://github.com/cweagans/docker-bg-sync&quot;&gt;docker-bg-sync&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As always, I hope you find this useful and your feedback is appreciated.&lt;/p&gt;
</description>
      <pubDate>Wed, 17 Nov 2021 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/speed-up-your-docker-developer-experience-on-macos/</guid>
    </item>
    <item>
      <title>Night-night OpenCover</title>
      <link>https://blog.many-monkeys.com/posts/night-night-opencover/</link>
      <description>&lt;p&gt;Over 10 years ago, I started developing OpenCover, an open-source code coverage tool for the .NET Framework. It started as a failed attempt to upgrade &lt;a href=&quot;https://github.com/sawilde/partcover.net4&quot;&gt;PartCover&lt;/a&gt; to be able to support 64-bit processes but ended with me starting from scratch and creating a &lt;a href=&quot;https://monkey-see-monkey-do-blog.herokuapp.com/open_cover_first_beta_release&quot;&gt;new code coverage tool&lt;/a&gt; that would support 32 and 64-bit processes on the Windows platform. It has been an interesting journey, I have met some wonderful people along the way and I learned a lot in the process of managing an open-source project and supporting the community. However, all good things come to an end and I feel this is the time for OpenCover development to cease whilst the memories are good. I wasn&#39;t sure how to finish this post so I decided to try out a Q&amp;amp;A format.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Q. Why now?&lt;/strong&gt;&lt;/em&gt;
A. First, &lt;em&gt;.NET Core&lt;/em&gt; - for OpenCover to support .NET Core was not going to be a trivial exercise, I felt it would need doing again from scratch and that wasn&#39;t a challenge I wanted to take on at this point. Next, &lt;em&gt;Maintenance&lt;/em&gt; - whilst there were no new features being added, there was still a constant maintenance cycle that had to be managed due to security patches; each cycle the task got more and more laborious with no real gain eg just recently the build pipeline failed because of an external dependency that moved location and I realised I didn&#39;t have the heart to fix it anymore - that is when I knew the time was right.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Q. What are you most proud of?&lt;/em&gt;&lt;/strong&gt;
A. I am not sure where to start? I could talk about the little gems I feel are in OpenCover such as the IL parser that is used to instrument the code or solving an awful performance issue by using shared memory buffers. Now I know this is going to sound trite, but actually, the thing I am most proud of is walking into a new workplace and finding they were using OpenCover and didn&#39;t have a clue I was the one who kicked the project off; that really made my day and made me realize people were actually using this on real projects.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Q. What would you do differently?&lt;/strong&gt;&lt;/em&gt;
A. I had to have a long and hard think on this one, I believe what I should have done was to have a proper roadmap, stick to what I feel was the right thing to do and, not be so eager to please. There were some features that took OpenCover away from its core purpose of providing code coverage for unit testing in a CI/CD pipeline, that only made the project more complicated to manage and probably caused more headaches than just saying no. It was my own time I was spending on solving other people&#39;s (usually work) problems and I was not getting paid for it; some people did buy me a coffee though.&lt;/p&gt;
&lt;p&gt;However, I didn&#39;t create OpenCover to make money but more to keep alive the knowledge I had from working on profilers back in 2005, especially as I felt that knowledge was leaving the community and only existed in the commercial realm.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Q. Would you sell OpenCover?&lt;/strong&gt;&lt;/em&gt;
A. &lt;strong&gt;No.&lt;/strong&gt; Nor, do I intend to relinquish control of the name. This may sound harsh but there are too many bad actors out there who would buy access to a product that currently has &lt;a href=&quot;https://www.nuget.org/packages/OpenCover/&quot;&gt;3K downloads&lt;/a&gt; a day (according to &lt;a href=&quot;https://www.nuget.org/packages/OpenCover/&quot;&gt;NuGet&lt;/a&gt;) and use it for evil. If you want to take over OpenCover then please fork it and give it a new name. Honestly, I won&#39;t mind, why should I, it is after all how OpenCover started in the first place. If you do, let me know and I&#39;ll happily redirect people to your codebase.&lt;/p&gt;
&lt;p&gt;Thanks again for supporting OpenCover over the years - night, night.&lt;/p&gt;
</description>
      <pubDate>Sun, 14 Nov 2021 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/night-night-opencover/</guid>
    </item>
    <item>
      <title>Scheduling AWS Lambdas, a 101</title>
      <link>https://blog.many-monkeys.com/posts/scheduled-lambdas-a-101/</link>
      <description>&lt;p&gt;I often find myself needing to schedule some automation and in the past I have (ab)used services such as Zapier or IFTTT (and other services of similar ilk) to achieve my goals. More recently I needed to do something for work, using the above services wouldn&#39;t cut it and I didn&#39;t have ready access to an internal cron-like service to do my bidding so I needed another approach.&lt;/p&gt;
&lt;p&gt;Though not immediately obvious, well not initially to me at least, you can use an Eventbridge (or CloudWatch events) trigger with a cron expression and use that to kick off your lambda on a particular schedule.&lt;/p&gt;
&lt;p&gt;To configure this in your &lt;code&gt;template.yml&lt;/code&gt; it would look something like this&lt;/p&gt;
&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;Resources&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;OperationToBeScheduled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; AWS&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;Serverless&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;Function
&lt;span class=&quot;token key atrule&quot;&gt;Properties&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	  &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;

  &lt;span class=&quot;token key atrule&quot;&gt;OperationToBeScheduledTrigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; AWS&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;Events&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;Rule
&lt;span class=&quot;token key atrule&quot;&gt;Properties&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; trigger our scheduled lambda
  &lt;span class=&quot;token key atrule&quot;&gt;ScheduleExpression&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cron(0 17 &lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt; * SUN &lt;span class=&quot;token important&quot;&gt;*)&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;Targets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;Arn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;!GetAtt&lt;/span&gt; OperationToBeScheduled.Arn

  &lt;span class=&quot;token key atrule&quot;&gt;OperationToBeScheduledLambdaPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; AWS&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;Lambda&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;Permission
&lt;span class=&quot;token key atrule&quot;&gt;Properties&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;FunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;!GetAtt&lt;/span&gt; OperationToBeScheduled.Arn
  &lt;span class=&quot;token key atrule&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;InvokeFunction
  &lt;span class=&quot;token key atrule&quot;&gt;Principal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; events.amazonaws.com
  &lt;span class=&quot;token key atrule&quot;&gt;SourceArn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;!GetAtt&lt;/span&gt; OperationToBeScheduledTrigger.Arn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, you need to create the trigger and configure the &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html&quot;&gt;ScheduleExpression&lt;/a&gt;. Next, you need to grant the trigger the right to invoke your lambda when it fires.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;cron&lt;/code&gt; expression is in UTC only so you&#39;ll need to do the mental gymnastics to get the trigger to activate according to your timezone and if necessary take daylight savings into account as well.&lt;/p&gt;
&lt;p&gt;The best part here is that I can have as many of these as I like and not have to take on any subscriptions with 3rd party services; though now I will probably need to keep more of an eye on my monthly AWS bill.&lt;/p&gt;
&lt;p&gt;The above snippet is for my future self and I hope you find it useful. Your feedback, as always, is appreciated.&lt;/p&gt;
</description>
      <pubDate>Fri, 15 Oct 2021 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/scheduled-lambdas-a-101/</guid>
    </item>
    <item>
      <title>Debugging lambdas in VSCode</title>
      <link>https://blog.many-monkeys.com/posts/debugging-lambdas-in-vscode/</link>
      <description>&lt;p&gt;I&#39;ve recently been doing some lambda development as part of my involvement with a hackathon known as Random Hack of Kindness. We ended up creating a small API using &lt;a href=&quot;https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html&quot;&gt;AWS-SAM-CLI&lt;/a&gt; and using typescript + webpack to build each lambda.&lt;/p&gt;
&lt;p&gt;The nice thing is that it is easy to run the lambda locally, so you don&#39;t need to constantly deploy to your AWS environment to test it. It also means that there is an opportunity to debug the lambda locally should the need arise; there are even plenty of instructions to make this work but none of them worked for me. I suspected the typescript + webpack combination was somehow involved but how to investigate it and if possible find a possible solution. All the applicable samples seemed to be plain javascript + node setups and were configured something like this.&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.2.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;configurations&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Attach to SAM CLI&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;request&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;attach&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;port&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5858&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;localRoot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;${workspaceRoot}/src/&amp;lt;path-to-lambda-function&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;remoteRoot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/var/task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;protocol&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;inspector&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;stopOnEntry&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sourceMaps&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I obviously tried the following&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.2.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;configurations&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Attach to SAM CLI&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;request&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;attach&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;port&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5858&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;localRoot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;${workspaceRoot}/dist/&amp;lt;path-to-lambda-function&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;remoteRoot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/var/task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;protocol&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;inspector&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;stopOnEntry&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sourceMaps&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It was always possible to attach the debugger but the breakpoints for them were never triggered. I even tried several of the source map options available in webpack before settling on &lt;code&gt;dev-tool: source-map&lt;/code&gt; as the one most likely to work.&lt;/p&gt;
&lt;p&gt;Could it be how the map files were being built? Inside the generated map files, there were references to &lt;code&gt;webpack:///...&lt;/code&gt; andI had seen other debug tutorials using &lt;code&gt;sourceMapPathOverrides&lt;/code&gt; in the &lt;code&gt;launch.json&lt;/code&gt; to assist the debugger in mapping these paths to the local paths; again tried various options but nothing seemed to help. Whilst reviewing the &lt;a href=&quot;https://webpack.js.org/configuration/&quot;&gt;webpack&lt;/a&gt; documentation, I saw that the &lt;code&gt;webpack:///...&lt;/code&gt; path appeared to be generated by &lt;code&gt;devtoolModuleFilenameTemplate&lt;/code&gt; and this could be overridden in the webpack config file, a common option being &lt;code&gt;[absolute-resource-path]&lt;/code&gt;. This produced a map file that had the full pathname and as this only going to be for local development builds I was not concerned about exposing my local drive paths; I can see why we wouldn&#39;t want this for files being distributed on websites though.&lt;/p&gt;
&lt;p&gt;Bingo - we can now debug. This is what I now have in my &lt;code&gt;webpack.config.ts&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Configuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
 &lt;span class=&quot;token literal-property property&quot;&gt;devtool&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; isProduction &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;source-map&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
 &lt;span class=&quot;token literal-property property&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
   &lt;span class=&quot;token literal-property property&quot;&gt;devtoolModuleFilenameTemplate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;[absolute-resource-path]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, I was still not satisfied because with the &lt;code&gt;localRoot&lt;/code&gt; setting the way it is, we could only debug one lambda at a time and we were planning on having many lambdas as part of the application we were developing, if we wanted to debug another lambda then we would have to update the &lt;code&gt;launch.json&lt;/code&gt;.  Changing the path to be something other than the lambda source location threw a message in the debug console that the &lt;code&gt;app.map.js&lt;/code&gt; file couldn&#39;t be found; note: this message only showed if you happened to have the console active at the time. Would it be possible to use one of the inline source map options instead? After some trial and error, I lucked upon the following combination that allowed me to debug each lambda without having to update the &lt;code&gt;launch.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;launch.json&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.2.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;configurations&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Attach to SAM CLI&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;request&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;attach&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;port&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5858&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;localRoot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;${workspaceRoot}/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;outFiles&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;${workspaceFolder}/dist/**/*.js&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;remoteRoot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/var/task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;protocol&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;inspector&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;stopOnEntry&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sourceMaps&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;webpack.config.ts&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Configuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
 &lt;span class=&quot;token literal-property property&quot;&gt;devtool&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; isProduction &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;eval-cheap-module-source-map&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
 &lt;span class=&quot;token literal-property property&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
   &lt;span class=&quot;token literal-property property&quot;&gt;devtoolModuleFilenameTemplate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;[absolute-resource-path]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I am still trying to determine which source map option is best and if it matters but at least we have a debug option available to us if we need it.&lt;/p&gt;
&lt;p&gt;As always these entries are a reminder to my future self but if you have any feedback or tips they&#39;ll be appreciated.&lt;/p&gt;
</description>
      <pubDate>Wed, 15 Sep 2021 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/debugging-lambdas-in-vscode/</guid>
    </item>
    <item>
      <title>AWS Control Tower, making my life easier</title>
      <link>https://blog.many-monkeys.com/posts/aws-control-tower/</link>
      <description>&lt;p&gt;I&#39;ve spent the past few weeks refreshing myself on the latest and greatest in the AWS IAM space and applying what I can to my own personal AWS account that I use for tinkering.&lt;/p&gt;
&lt;p&gt;A recommendation is to have one master organisation (org) and then create a separate org to hold all the audit and log data (some guidance I came across also says to have one org for audit and another for logs) and then create other orgs for your production, testing, etc environments. The setup for such was going to take quite some time and probably a bit too much for a simple dev account. However, these types of setups are the sort of environment that I spend my working life in and I have had very little insight into what is happening behind the scenes. Now, I could&#39;ve followed the rather tedious instructions (and probably make a lot of mistakes along the way) to do this manually or I can use AWS Control Tower to do the heavy lifting and then look at the final outcome and tinker with it, so that is what I did.&lt;/p&gt;
&lt;p&gt;Once the process was complete (had to create 3 additional email accounts) I was left with my original org as &lt;code&gt;Root&lt;/code&gt; and two additional child orgs.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Security&lt;/code&gt; - with two AWS accounts, that I&#39;ll refer to as &lt;code&gt;audit&lt;/code&gt; and &lt;code&gt;log-archive&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Sandbox&lt;/code&gt; - with a single AWS account, that I&#39;ll call &lt;code&gt;sandbox&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I did notice that after the AWS Control Tower process was complete I wasn&#39;t really sure what to do next or even if there was something I should be doing to make my life a little easier.&lt;/p&gt;
&lt;h3&gt;Securing&lt;/h3&gt;
&lt;p&gt;At no point did I have to create any passwords for the three additional accounts and so adding complex passwords (thank heavens for password managers) and securing with 2FA was the next chore. Feeling a bit better, I wanted to see what was going on in the &lt;code&gt;Security&lt;/code&gt; org and the resources they were holding. Swapping between accounts quickly became tedious (password + code) and I knew I needed to set up roles in each of the new accounts that would allow my IAM account in the root org to jump between orgs and see the resources within.&lt;/p&gt;
&lt;h3&gt;Account Aliases and Roles&lt;/h3&gt;
&lt;p&gt;AWS loves their 12 digit numbers but they are hard to remember and so I make use of account aliases as much as I can. Unfortunately all the good (and obvious/simple) aliases have gone and so you&#39;ll probably need to be inventive, but if you&#39;re lucky you&#39;ll find something you can tolerate.&lt;/p&gt;
&lt;p&gt;In each of the three new accounts, I created a role called &lt;code&gt;admin&lt;/code&gt; that granted the &lt;code&gt;AdministratorAccess&lt;/code&gt; policy to the root account, using the &lt;code&gt;Another AWS account&lt;/code&gt; flow; I also took the opportunity to give each account a simple alias. AWS Control tower also creates similar roles but they are extremely wordy (ie long and hard to remember) and also differ in name from account to account.&lt;/p&gt;
&lt;p&gt;With these new roles in place, I can now log-in to the original root account as my IAM user (&lt;strong&gt;not&lt;/strong&gt; the root user) and then use the &lt;code&gt;Switch Roles&lt;/code&gt; feature to hop between the &lt;code&gt;Root&lt;/code&gt;, &lt;code&gt;Security&lt;/code&gt; and &lt;code&gt;SandBox&lt;/code&gt; orgs quickly. For the account, I could use the account alias rather than the number and so in the UI so rather than &lt;code&gt;admin @ 123456789012&lt;/code&gt;, you see &lt;code&gt;admin @ &amp;lt;alias&amp;gt;&lt;/code&gt; which is a lot easier to remember.&lt;/p&gt;
&lt;p&gt;If I had other users in my account then I would look into creating roles with fewer permissions (ie read-only) in the &lt;code&gt;Security&lt;/code&gt; org and allowing others the use of that role instead.&lt;/p&gt;
&lt;p&gt;As always this is a note to my future self but your feedback is appreciated.&lt;/p&gt;
</description>
      <pubDate>Tue, 31 Aug 2021 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/aws-control-tower/</guid>
    </item>
    <item>
      <title>Upgrading to Ghost v4 on Heroku</title>
      <link>https://blog.many-monkeys.com/posts/upgrading-to-ghost-v4-on-heroku/</link>
      <description>&lt;p&gt;If you&#39;ve read any of my earlier posts you&#39;ll know that I have been running the administrative side of my blog (using &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost&lt;/a&gt;) on &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;. But in this age, things move quickly and Ghost has since updated to v4 but looking at their docs the &lt;a href=&quot;https://ghost.org/docs/update/&quot;&gt;supported&lt;/a&gt; upgrade path is all around the &lt;a href=&quot;https://www.npmjs.com/package/ghost-cli&quot;&gt;ghost-cli&lt;/a&gt; tooling. However, as I didn&#39;t use the ghost-cli to create this installation then I&#39;ll need to resort to some manual steps.&lt;/p&gt;
&lt;p&gt;As I had already trimmed the installation down to the bare bones that I required for headless operation, updating to the latest v3 flavour (as mentioned in the upgrade docs) of Ghost was trivial. Throwing caution to the wind, I forced the ghost version to the latest version and gave it a go. And... nope.&lt;/p&gt;
&lt;p&gt;A quick delve and it seems all that that is required is a small change in to how Ghost is launched.&lt;/p&gt;
&lt;p&gt;ie change &lt;code&gt;server.js&lt;/code&gt; (as used in v3)&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; ghost &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;ghost&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Run a single Ghost process&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;ghost&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;ghostServer&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; ghostServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Ghost server error: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stack&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to now be&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;ghost&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Try again and the blog part of the site now launches. Now let&#39;s try the admin side and have a look at the new features. Uh-oh.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/d1199947-584c-47d8-8701-a13c0b7cfdfb/ScreenShot20210824at22946pm.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;admin error&lt;/p&gt;
&lt;p&gt;No solution forthcoming from the only other similar issue raised several months ago (that I could find). That number `3.0.0` just looks suspicious and the only place I could find it was in the package.json (version), a quick tweak and the message changed to match the version. So the final changes to my package.json was&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/7563678e-80f3-4901-92f8-f33dd2e51642/ScreenShot20210824at22710pm.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;package.json changes&lt;/p&gt;
&lt;p&gt;And now I have a working v4 blog that I can push to Heroku.&lt;/p&gt;
&lt;p&gt;Well other than that subtle issue with accessing the admin side of things that was relatively painless.&lt;/p&gt;
&lt;h2&gt;Heroku Pipelines&lt;/h2&gt;
&lt;p&gt;Up until now, I have been pushing direct to Heroku and then pushing a backup to Github. I am lazy (as well as cheap) and I only want to push once so I have now switched to using a Heroku pipeline and now when any changes are pushed to Github they are picked up by Heroku.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/597767cf-c812-4b99-9064-470a69c34d85/ScreenShot20210824at22552pm.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Heroku pipeline&lt;/p&gt;
&lt;p&gt;A cute thing that this enables is that I can now see my Heroku environment on Github.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/47aada46-5cc6-4eae-90ab-1403a36f150a/ScreenShot20210824at22454pm.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As usual, these posts are to remind my future self of what I was doing at the time, but your feedback is nonetheless still appreciated.&lt;/p&gt;
</description>
      <pubDate>Tue, 24 Aug 2021 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/upgrading-to-ghost-v4-on-heroku/</guid>
    </item>
    <item>
      <title>Oh my zsh...</title>
      <link>https://blog.many-monkeys.com/posts/oh-my-zsh/</link>
      <description>&lt;p&gt;When I moved to using a Mac for development and working on projects involving React.js etc I knew I was going to have to reintroduce myself to the command line and so I started a search around what is considered to be the best terminal emulator and shell to use. During this search, I stumbled across &lt;a href=&quot;https://ohmyz.sh/&quot;&gt;oh-my-zsh&lt;/a&gt; and I was an immediate convert.  To quote the developers:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Oh My Zsh is a delightful, open source, community-driven framework for managing your Zsh configuration. It comes bundled with thousands of helpful functions, helpers, plugins, themes, and a few things that make you shout...&lt;/p&gt;
&lt;p&gt;&amp;quot;Oh My ZSH!&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So after installing iTerm2 (the product of my original search) and switching zsh for my shell, I installed oh-my-zsh and started configuring it.&lt;/p&gt;
&lt;h2&gt;Themes&lt;/h2&gt;
&lt;p&gt;What immediately got my attention when I came across oh-my-zsh was the git integration and the ability for the terminal to show the git status of the folder I was currently in. Now all the themes appear to support this but the theme that really caught my eye was &lt;a href=&quot;https://github.com/romkatv/powerlevel10k&quot;&gt;powerlevel10k&lt;/a&gt;, the clever use of fonts really condensed the information I needed to know; I finally settled on &lt;a href=&quot;https://github.com/romkatv/powerlevel10k#meslo-nerd-font-patched-for-powerlevel10k&quot;&gt;MesloLGS NF&lt;/a&gt; as my preferred font (it&#39;s a personal choice).&lt;/p&gt;
&lt;p&gt;I use VSCode a lot and use the built-in terminal when live sharing during pairing sessions, so I wanted the same experience there, adding the following to the settings in VSCode resolved that.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token string-property property&quot;&gt;&quot;terminal.external.osxExec&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;iterm.app&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token string-property property&quot;&gt;&quot;terminal.integrated.fontFamily&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&#39;MesloLGS NF&#39;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/01bd7cd1-26fa-4139-9cce-1f24f4b35c9f/ScreenShot20210824at61953pm.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Plugins&lt;/h2&gt;
&lt;p&gt;There are lots of plugins and I haven&#39;t even begun to explore them all and I am wary that too many plugins will really impact the shell loading times, though I believe that powerlevel10k has a workaround for that called instant prompt.&lt;/p&gt;
&lt;h3&gt;git&lt;/h3&gt;
&lt;p&gt;I think it goes without saying that I have this plugin enabled, it also comes with lots of useful aliases (of which I know about 10% of them).&lt;/p&gt;
&lt;h3&gt;asdf&lt;/h3&gt;
&lt;p&gt;I am constantly switching between node versions and I use &lt;a href=&quot;http://asdf-vm.com/guide/getting-started.html#getting-started&quot;&gt;asdf&lt;/a&gt; to manage which node version I should be using when it is important I am not using the default. The oh-my-zsh plugin shows the current version as part of the prompt. Though I only use asdf for managing node installations it supports many other languages such as ruby, elixir, erlang, and countless other community contributions.&lt;/p&gt;
&lt;h3&gt;zsh-autosuggestions&lt;/h3&gt;
&lt;p&gt;This plugin provides auto-suggestions as you type and is a great time saver.&lt;/p&gt;
&lt;h3&gt;zsh-syntax-highlighting&lt;/h3&gt;
&lt;p&gt;This plugin provides syntax colouring as you type and helps cut down on the obvious typos, alongside `zsh-autosuggestions` this has improved my command line experience.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/f6248395-396d-40d2-85ac-058fa107cb03/ScreenShot20210824at64257pm.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Other plugins&lt;/h3&gt;
&lt;p&gt;100s exist, some are novelty ie chuck norris, cow talk etc and I am not so bothered about those long term - good for a laugh but in the end pointless.&lt;/p&gt;
&lt;p&gt;Your thoughts are, as usual, appreciated.&lt;/p&gt;
</description>
      <pubDate>Sat, 24 Jul 2021 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/oh-my-zsh/</guid>
    </item>
    <item>
      <title>Sharing &quot;developer&quot; secrets</title>
      <link>https://blog.many-monkeys.com/posts/sharing-secrets/</link>
      <description>&lt;p&gt;Committing secrets to source control is a real problem for developers and I, like many others, have done it at least once. When it happens, the team then has to go through the awful process of updating the affected secrets and, if required, removing those secrets from source control as well (assuming they got pushed to a central location.)&lt;/p&gt;
&lt;p&gt;Sometime ago, I came across a feature in .net core that allows you to store secrets in a json file that is part of you user profile and can be loaded by your application. By default it uses a new location for every application but with a little tinkering you can use the same location for several applications. The magic works due to the ability to &amp;quot;layer&amp;quot; configuration from multiple sources when using &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.configurationbuilder?view=dotnet-plat-ext-5.0&quot;&gt;ConfigurationBuilder&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; builder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;ConfigurationBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetBasePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Directory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddJsonFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;appsettings.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token named-parameter punctuation&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token named-parameter punctuation&quot;&gt;reloadOnChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;AddUserSecrets&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Program&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddEnvironmentVariables&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then applying the &lt;code&gt;UserSecretsIdAttribute&lt;/code&gt; that you can either set as an assembly attribute&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token target keyword&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;UserSecretsId&lt;/span&gt;&lt;span class=&quot;token attribute-arguments&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;8d49e500-1a72-4596-bdfa-e56080b10b5f&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or you can set it directly in the project file, which is more common for .net core projects.&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;UserSecretsId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;8d49e500-1a72-4596-bdfa-e56080b10b5f&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;UserSecretsId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once this is set in the project you can then access the &lt;code&gt;secrets.json&lt;/code&gt; file from the location in the user profile and start overriding your configuration and not worry about the secrets being committed to source control.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/8ee008dc-2939-473a-8f78-5c2bec2dfcfc/Manageusersecrets.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;e.g. if in your config you wanted to override a specific field&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then you can override this in the &lt;code&gt;secrets.json&lt;/code&gt; like so, take note of the flattening of the json object that happens&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;object:key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;secret-data-here&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The by using the same identifier, usually a GUID, across multiple &amp;quot;application&amp;quot; projects will allow you to have a shared set of secrets for those applications. Of course you may prefer to use environment variables or even pull the secrets from a secure location e.g. Azure KeyVault, but it is nice to have options.&lt;/p&gt;
&lt;p&gt;Like most of my posts these entries are more notes for my future self but from which others may benefit. Your feedback is appreciated.&lt;/p&gt;
</description>
      <pubDate>Fri, 04 Dec 2020 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/sharing-secrets/</guid>
    </item>
    <item>
      <title>Using Ghost as a headless CMS (part 2)</title>
      <link>https://blog.many-monkeys.com/posts/using-ghost-as-a-headless-cms-part-2/</link>
      <description>&lt;p&gt;So getting around to this took a lot longer than I thought it would but I eventually made the switch and now I am running my blog using a self hosted &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost&lt;/a&gt; using &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt; and I am also using a &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt; generated blog (uses React) with &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; as the build and hosting tool. Why so long? Well there were a few integrations I wanted to make sure I could get working properly before I finally switched over from a managed Ghost platform.&lt;/p&gt;
&lt;p&gt;For a starting point I used the &lt;a href=&quot;https://jamstackthemes.dev/cms/ghost/&quot;&gt;JAMStack Ghost/Gatsby&lt;/a&gt; starter from &lt;a href=&quot;https://github.com/styxlab/gatsby-starter-try-ghost&quot;&gt;styxlab&lt;/a&gt; and added a few tweaks to the &lt;a href=&quot;https://github.com/styxlab/gatsby-theme-try-ghost&quot;&gt;theme&lt;/a&gt; that comes with it. I chose this theme as it has a few features built into it that I like e.g. Infinite Scroll, and looks to have an active community in case if I have any issues.&lt;/p&gt;
&lt;h3&gt;Disqus integration&lt;/h3&gt;
&lt;p&gt;I&#39;ve been using &lt;a href=&quot;https://disqus.com/&quot;&gt;Disqus&lt;/a&gt; for comment management for a few years and so I wanted to make sure I could hook that into the new theme. There is already a Disqus &lt;a href=&quot;https://www.gatsbyjs.com/plugins/gatsby-plugin-disqus/&quot;&gt;package&lt;/a&gt; for Gatsby and so getting started was relatively easy. What I initially stalled on was working out how to customise the Gatsby theme such that the Disqus component would load and to do this I needed to understand what a theme means in Gatsby; it isn&#39;t just CSS and images that I am more familiar with, with Gatsby you can also override the React components.&lt;/p&gt;
&lt;p&gt;First I needed to identify the component I needed to shadow and then add the modified component to my own repository in the correct location. Looking at the template &lt;code&gt;page.js&lt;/code&gt; in &lt;code&gt;node_modules&#92;gatsby-theme-try-ghost&#92;src&#92;templates&lt;/code&gt; there is a &lt;code&gt;Comments&lt;/code&gt; component that looked like an ideal candidate and this component can be found in &lt;code&gt;node_modules&#92;gatsby-theme-try-ghost&#92;src&#92;components&#92;common&lt;/code&gt;. The &lt;code&gt;Comments.js&lt;/code&gt; is just a stub&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/**
*
* Placeholder for Comments
*
*/&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The actual component&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Comments
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To shadow this I copied this to my repository and placed it in its shadow location i.e. &lt;code&gt;node_modules&#92;gatsby-theme-try-ghost&#92;src&#92;components&#92;common&#92;comments.js&lt;/code&gt; to &lt;code&gt;src&#92;gatsby-theme-try-ghost&#92;components&#92;common&#92;comments.js&lt;/code&gt;. Finally, I modified the component to bring in the Disqus component&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; PropTypes &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;prop-types&#39;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Disqus &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;gatsby-plugin-disqus&#39;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; disqusConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Disqus config&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;disqusConfig&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

Comments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;propTypes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PropTypes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Comments
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To test this I updated my Disqus site to allow comments to appear on any site on my domain so I could view this on the development site I had hooked up on Netlify.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/40defb4a-477b-4c48-a70f-7f519895e7ab/disqus.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I did notice that not all the blog posts had hooked up properly but you can use the management tools within Disqus to move the comments onto the correct pages.&lt;/p&gt;
&lt;h3&gt;Algolia integration&lt;/h3&gt;
&lt;p&gt;I&#39;ve been using &lt;a href=&quot;https://www.algolia.com/&quot;&gt;Algolia&lt;/a&gt; as a search engine on the site for a few years and I didn&#39;t want to lose that functionality as I use it myself to find specific articles. Getting started was again easy as I followed the &lt;a href=&quot;https://www.gatsbyjs.com/docs/adding-search-with-algolia/&quot;&gt;tutorial&lt;/a&gt; on the Gatsby site but because I was using Ghost rather than markdown then I needed to make a few tweaks. First I modified GraphQL in the starter &lt;code&gt;algolia-queries.js&lt;/code&gt; to fetch the the from Ghost instead&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; indexName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;sitePages&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pageQuery &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
{
  pages: allGhostPost {
edges {
  node {
    id
    updated_at
    slug
    title
    plaintext
    excerpt
    tags {
      name
      description
    }
  }
}
  }
}&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pageToAlgoliaRecord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;rest &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;objectID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;rest&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; queries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pageQuery&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token function-variable function&quot;&gt;transformer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;edges&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pageToAlgoliaRecord&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
indexName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;attributesToSnippet&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;excerpt:20&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; queries
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, once the index was built on Algolia, I made some small changes to the default behaviour in Algolia to make the returned results a little more efficient (by default it returns the whole search document).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/ad5be52f-a7cf-42f3-bda5-1aec14b4e8d5/retrieve_attr.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;With all this in place and the Search component added to the site the results are presented like this&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/7cc5b60f-e9fb-4966-894f-619ec8cdfed1/search_site.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;However after each update to the site or adding a new post (i.e. this one) the returned data being returned as part of the query results had reverted to returning everything again. It seemed that all my manual settings had been undone except for the &lt;code&gt;excerpt:20&lt;/code&gt; in the &lt;code&gt;attributesToSnippet&lt;/code&gt; section which I was supplying as part of my query above, it seems I am required to supply all these &lt;a href=&quot;https://www.algolia.com/doc/guides/managing-results/must-do/searchable-attributes/#searchable-attributes-overview&quot;&gt;settings&lt;/a&gt; rather than set them in the Algolia UI, so...&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; queries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pageQuery&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token function-variable function&quot;&gt;transformer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;edges&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pageToAlgoliaRecord&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
indexName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;attributesToSnippet&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;excerpt:20&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;searchableAttributes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;tags.name, tags.description&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;unordered(plaintext)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;attributesToRetrieve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;excerpt&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the above integrations eventually in place, and sticking, I flipped the switch and moved to being a completely self managed Heroku+Ghost+Netlify+Gatsby blog.&lt;/p&gt;
&lt;p&gt;One final advantage of pushing directly to Aloglia during  the build process is that I can now deactivate the &lt;a href=&quot;https://monkey-see-monkey-do-blog.herokuapp.com/adding-search-to-your-ghost-blog-part-2&quot;&gt;Zapier+Azure&lt;/a&gt; integration I was using when I first added Algolia support to my site.&lt;/p&gt;
&lt;p&gt;[Update 18 Nov 2020] Some time back I blogged about &lt;a href=&quot;https://monkey-see-monkey-do-blog.herokuapp.com/adding-a-tags-page-to-ghost-blog&quot;&gt;creating a tags&lt;/a&gt; page so I could see all the tags I had created and find articles by those tags. I decided to repeat the task with the new site by taking inspiration from the &lt;a href=&quot;https://github.com/styxlab/gatsby-theme-try-ghost&quot;&gt;starter theme&lt;/a&gt; and used a similar approach used to display the posts. Starting with a copy of &lt;a href=&quot;https://github.com/styxlab/gatsby-theme-try-ghost/blob/master/packages/gatsby-theme-try-ghost/src/templates/index.js&quot;&gt;index.js&lt;/a&gt; and customising the GraphQL query to fetch the tag data instead, including the post count. Then I created new components to finally display the tags in the same 1,3,2 pattern layout.&lt;/p&gt;
&lt;p&gt;As always your thoughts are appreciated.&lt;/p&gt;
</description>
      <pubDate>Sun, 15 Nov 2020 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/using-ghost-as-a-headless-cms-part-2/</guid>
    </item>
    <item>
      <title>SSH tunneling from a Docker container</title>
      <link>https://blog.many-monkeys.com/posts/tunneling-from-a-container/</link>
      <description>&lt;p&gt;In a &lt;a href=&quot;https://monkey-see-monkey-do-blog.herokuapp.com/setting-up-a-bastion-server-on-aws-2&quot;&gt;previous post&lt;/a&gt; I mentioned the approach I took to secure an RDS server behind a bastion server being hosted on AWS. Using SSH to create a tunnel to access this resources is well &lt;a href=&quot;https://www.ssh.com/ssh/tunneling/example&quot;&gt;documented&lt;/a&gt; and so there is no need to labour on that. However I also needed to access these resources from applications that are running on &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; containers running elsewhere. I am sure there is more than one way to achieve this but I will describe the approach I took and has so far proven to be pretty stable.&lt;/p&gt;
&lt;p&gt;I dismissed any code based options as they just made the application more complex to develop and test and instead went for an approach that was purely container based. To do this I used two applications&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://linux.die.net/man/1/autossh&quot;&gt;AutoSSH&lt;/a&gt; - to set up the SSH tunnel and maintain it,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://supervisord.org/&quot;&gt;Supervisor&lt;/a&gt; - to execute and run/monitor multiple programs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;AutoSSH is obvious but why did I need Supervisor? Well a container only has a single ENTRYPOINT (or CMD) which can be used to run an application or a script but in this case I needed to run several (at least two) applications at the same time and for both applications to stay running. This could be managed by scripts but I decided to give Supervisor a try instead.&lt;/p&gt;
&lt;h3&gt;Adding Supervisor and AutoSSH to the container&lt;/h3&gt;
&lt;p&gt;Initially I was running a dotnet application and launching it like so in my Dockerfile&lt;/p&gt;
&lt;pre class=&quot;language-docker&quot;&gt;&lt;code class=&quot;language-docker&quot;&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; base &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; final&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;WORKDIR&lt;/span&gt; /app&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; &lt;span class=&quot;token options&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;publish&lt;/span&gt;&lt;/span&gt; /app/publish .&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ENTRYPOINT&lt;/span&gt; [&lt;span class=&quot;token string&quot;&gt;&quot;dotnet&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;My.Application.dll&quot;&lt;/span&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I updated this section to fetch AutoSSH and Superisor and install them&lt;/p&gt;
&lt;pre class=&quot;language-docker&quot;&gt;&lt;code class=&quot;language-docker&quot;&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; base &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; final&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# install additional packages&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; mkdir -p /var/log/supervisor /run/sshd&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; apt-get update &amp;amp;&amp;amp; apt-get install -y supervisor autossh&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# configure supervisor&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; mkdir -p /var/log/supervisor&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; [&lt;span class=&quot;token string&quot;&gt;&quot;web/My.Application/supervisord.conf&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;/etc/supervisor/conf.d/supervisord.conf&quot;&lt;/span&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# install certificates&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; [&lt;span class=&quot;token string&quot;&gt;&quot;web/My.Application/certs/rds-ca-2019-root.crt&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;/usr/local/share/ca-certificates/&quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; chmod 644 /usr/local/share/ca-certificates/rds-ca-2019-root.crt&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; [&lt;span class=&quot;token string&quot;&gt;&quot;web/My.Application/certs/rds-ca-2019-ap-southeast-2.crt&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;/usr/local/share/ca-certificates/&quot;&lt;/span&gt;]&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; chmod 644 /usr/local/share/ca-certificates/rds-ca-2019-ap-southeast-2.crt&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; update-ca-certificates&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# copy application&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;WORKDIR&lt;/span&gt; /app&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; &lt;span class=&quot;token options&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;publish&lt;/span&gt;&lt;/span&gt; /app/publish .&lt;/span&gt;

&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ENTRYPOINT&lt;/span&gt; [&lt;span class=&quot;token string&quot;&gt;&quot;/usr/bin/supervisord&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;-c&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;/etc/supervisor/conf.d/supervisord.conf&quot;&lt;/span&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally in the &lt;code&gt;supervisord.conf&lt;/code&gt; I configured it to launch AutoSSH and the original dotnet application.&lt;/p&gt;
&lt;pre class=&quot;language-ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;supervisord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;nodaemon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;logfile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;/share/conf/logs/supervisord/supervisord.log&lt;/span&gt;

&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;program:dotnet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;/usr/bin/dotnet /app/My.Application.dll&lt;/span&gt;

&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;program:autossh&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;autossh -M 0 -o &quot;ServerAliveInterval 30&quot; -o &quot;ServerAliveCountMax 3&quot; -i %(ENV_SSH_ARGS_KEYPATH)s -N -L %(ENV_SSH_ARGS_MAPPING)s &quot;-o UserKnownHostsFile=/dev/null&quot; &quot;-o StrictHostKeyChecking=no&quot; %(ENV_SSH_ARGS_HOSTNAME)s&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;stdout_logfile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;/share/conf/logs/supervisord/autossh.log&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;redirect_stderr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;/share&lt;/code&gt; folder is actually a file mount so that we can preserve the logs for later analysis. The key file is also hosted on a secured file mount and passed in via the environment variable &lt;code&gt;SSH_ARGS_KEYPATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It is probably overkill to use Supervisor like this but it was a lot simpler (and I feel easier for others to follow) than writing lots of shell scripts to achieve the same.&lt;/p&gt;
&lt;p&gt;As always your feedback is appreciated.&lt;/p&gt;
</description>
      <pubDate>Sat, 05 Sep 2020 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/tunneling-from-a-container/</guid>
    </item>
    <item>
      <title>Setting up a bastion server on AWS</title>
      <link>https://blog.many-monkeys.com/posts/setting-up-a-bastion-server-on-aws-2/</link>
      <description>&lt;p&gt;I recently had a need to further secure an RDS server so that it was no longer publicly facing but would instead be accessed via SSH. It is easy to mess something like that up if you need to setup all the parts manually but thankfully AWS have a &lt;a href=&quot;https://aws.amazon.com/quickstart/architecture/linux-bastion/&quot;&gt;quick start&lt;/a&gt; that does the majority of the heavy lifting. Once the deployment was finished I could move the RDS so that it lived on the private subnet but even when I was connected to the bastion server I couldn&#39;t connect to the RDS server.&lt;/p&gt;
&lt;p&gt;What the quick start doesn&#39;t give any guidance on is what to do next once you have this all setup so what was missing? This is probably immediately obvious to anyone who lives and breaths AWS everyday but what was missing was than I needed to update the security group for the private subnet to allow Inbound traffic from the public subnet where the bastion server resides. Being picky I limited the access to just the ports I needed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/d8846bef-b951-4235-959f-f082a049cf79/security_group.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once I could connect to the RDS server from the bastion server (I used netcat to test this), I then updated the Inbound rules of the security group so that only specific IP ranges could connect to the bastion server using SSH. To test the SSH tunnel I needed to enable SSH tunneling by setting &lt;code&gt;AllowTcpForwarding yes&lt;/code&gt; in the &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;, followed by &lt;code&gt;sudo systemctl restart sshd.service&lt;/code&gt; to allow the new settings to take effect.&lt;/p&gt;
&lt;h3&gt;Adding more users&lt;/h3&gt;
&lt;p&gt;Now that the RDS server was secured I needed to allow others access to the same RDS server via the SSH tunnel but I also wanted to restrict them to SSH tunneling, i.e. no interactive sessions on the bastion server. To achieve this I created a linux user that could be restricted to SSH tunneling only and would be used by the other users of the RDS&lt;/p&gt;
&lt;p&gt;First, create a new linux user and switch to it&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;sudo adduser -m bastion
sudo passwd bastion
su - bastion&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then, create a .ssh folder and add an authorized keys file to host the public keys of each user&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;mkdir .ssh
chmod 700 .ssh
cd .ssh
touch authorized_keys
chmod 600 authorized_keys
nano authorized_keys&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then add each public key (e.g. &lt;code&gt;.ssh&#92;id_rsa.pub&lt;/code&gt;) of each user that needs access. Finally as we don&#39;t want the &amp;quot;bastion&amp;quot; user to have an interactive session over SSH we add the following entry to the bottom of &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; and restart the &lt;code&gt;sshd&lt;/code&gt; service again.&lt;/p&gt;
&lt;p&gt;Match User bastion
ForceCommand echo &#39;This account can only be used for tunnelling&#39;&lt;/p&gt;
&lt;p&gt;With this in place, only users with the correct private keys and on the expected networks can connect to the RDS server via the SSH tunnel.&lt;/p&gt;
&lt;p&gt;I am sure there are other ways to achieve this.&lt;/p&gt;
&lt;p&gt;[Update 18/11/2020] I would also recommend reading up on &lt;a href=&quot;https://www.cyberciti.biz/tips/linux-unix-bsd-openssh-server-best-practices.html&quot;&gt;best practices&lt;/a&gt; for securing your bastion server as these change as we learn more about the threats we face.&lt;/p&gt;
&lt;p&gt;As always your feedback is important.&lt;/p&gt;
</description>
      <pubDate>Tue, 01 Sep 2020 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/setting-up-a-bastion-server-on-aws-2/</guid>
    </item>
    <item>
      <title>Using Ghost as a headless CMS</title>
      <link>https://blog.many-monkeys.com/posts/using-ghost-as-a-headless-cms/</link>
      <description>&lt;p&gt;In a previous post I described how I investigated hosting ghost for free using Heroku and how this will allow me to potentially pull data from Ghost and build it into a static site which I can also get hosted for free (or at least a lot cheaper than what I am currently paying). I did spend some time investigating various site scrapers that would pull the ghost content directly and build a static site and though I could get these (mostly) working locally I couldn&#39;t find anyway to run them simply/cheaply in the cloud so that I could automate the process and make the effort of getting the scraper work properly worth it.&lt;/p&gt;
&lt;p&gt;Ghost however refers to itself as a headless CMS and so I thought that I&#39;ll look into what the community is doing in this space and this is how I came across Gatsby and the deployment/hosting platform called Netlify, as I had a few false starts I&#39;ll describe how I got it to work.&lt;/p&gt;
&lt;h2&gt;Installing and running Gatsby&lt;/h2&gt;
&lt;p&gt;First download the Gatsby CLI tool using npm and then prepare the starter project that is pre-configured to pull data from Ghost via its API.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; gatsby-cli
gatsby new gatsby-blog-ghost https://github.com/TryGhost/gatsby-starter-ghost&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a folder called &lt;code&gt;gatsby-blog-ghost&lt;/code&gt; and inside it will be, after a little configuration, all that is needed to build a static site from the Ghost platfrom.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;From the Ghost admin portal create a custom integration&lt;/li&gt;
&lt;li&gt;Update the production entry in `.ghost.json` (found in the &lt;code&gt;gatsby-blog-ghost&lt;/code&gt; folder) with the supplied API key and API URL&lt;/li&gt;
&lt;li&gt;Test the settings work by and navigating to the supplied URL e.g. http://localhost:9000&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;gatsby build
gatsby serve&lt;/p&gt;
&lt;h3&gt;The downside&lt;/h3&gt;
&lt;p&gt;The default theme is a not really to my liking and if I want my disqus and algolia integrations then I&#39;ll need to do some work on the theme, once I have found one that I like.&lt;/p&gt;
&lt;h3&gt;Automating the Gatsby build using Netlify&lt;/h3&gt;
&lt;p&gt;To get &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; to build and host the blog requires us to push the Gatsby folder created earlier to an online git repository site such as &lt;a href=&quot;https://github.com/&quot;&gt;Github&lt;/a&gt; and then configure Netlify to build the site from that repository.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a private repository on github and add the remote to the git repository in &lt;code&gt;gatsby-blog-ghost&lt;/code&gt; and push all changes.&lt;/li&gt;
&lt;li&gt;Using Netlify, create a &amp;quot;new site from git&amp;quot; and select the private repository. Netlify will immediately start building your site (and will do so on any change to that repository) and deploy it to the configured netlify.com site.&lt;/li&gt;
&lt;li&gt;Automate Netlify to rebuild on ghost site changes by configuring a webhook (Settings/Build &amp;amp; Deploy) and then adding that webhook to the integration created in Ghost to be called when &amp;quot;Site changed (rebuild)&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now what we have is a &lt;a href=&quot;https://monkey-see-monkey-do-blog.netlify.com/&quot;&gt;static site&lt;/a&gt; that will always rebuild whenever the blog is updated whether it be due to changes in content or theme.&lt;/p&gt;
&lt;h3&gt;Configuring the Netlify site to run as a subdomain&lt;/h3&gt;
&lt;p&gt;I has some initial issues getting this to work with my Cloudflare DNS as it felt like I had to move my &lt;a href=&quot;https://www.netlify.com/blog/2017/03/28/why-you-dont-need-cloudflare-with-netlify&quot;&gt;DNS to Netlify&lt;/a&gt; and I didn&#39;t want to do that, however after some trial and error I managed to get this to work and now the Heroku hosted Ghost site is now being rendered using Gatsby as a &lt;a href=&quot;https://netlify.many-monkeys.com/&quot;&gt;subdomain&lt;/a&gt; of my main site.&lt;/p&gt;
&lt;h3&gt;Automating the Gatsby build using Render&lt;/h3&gt;
&lt;p&gt;This is virtually identical to using Netlify to build and deploy.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a private repository on github and add the remote to the git repository in &lt;code&gt;gatsby-blog-ghost&lt;/code&gt; and push all changes.&lt;/li&gt;
&lt;li&gt;Using &lt;a href=&quot;https://render.com/&quot;&gt;Render&lt;/a&gt;, create a &amp;quot;New Web Service&amp;quot; and select the private repository. Render will identify the repository as a Gatsby site and set some defaults and then once confirmed will immediately start building your site (and will do so on any change to that repository) and deploy it to the configured render.com site.&lt;/li&gt;
&lt;li&gt;Automate Render to rebuild on ghost site changes by configuring a webhook (Settings/Deploy Hook) and then adding that webhook to the integration created in Ghost to be called when &amp;quot;Site changed (rebuild)&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now what we have is a &lt;a href=&quot;https://monkey-see-monkey-do-gatsby-ghost-starter.onrender.com/&quot;&gt;static site&lt;/a&gt; that will always rebuild whenever the blog is updated whether it be due to changes in content or theme.&lt;/p&gt;
&lt;h3&gt;Configuring the Render site to run as a subdomain&lt;/h3&gt;
&lt;p&gt;This felt like it was a lot easier than configuring Netlify but this could also because I was now more familiar with the overall DNS configuration in Cloudflare and now the Heroku hosted Ghost site is now being rendered using Gatsby as a &lt;a href=&quot;https://render.many-monkeys.com/&quot;&gt;subdomain&lt;/a&gt; of my main site.&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;I think Gatsby may be the way to go here as I think just a little bit of theme-ing will be a lot simpler than getting a static scraper to work and then finding somewhere to host it.&lt;/p&gt;
&lt;p&gt;Your feedback is appreciated&lt;/p&gt;
</description>
      <pubDate>Sun, 05 Jan 2020 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/using-ghost-as-a-headless-cms/</guid>
    </item>
    <item>
      <title>Hosting Ghost For Free</title>
      <link>https://blog.many-monkeys.com/posts/hosting-ghost-for-free/</link>
      <description>&lt;p&gt;I&#39;ve been running my blog on a paid &lt;a href=&quot;https://github.com/TryGhost/Ghost&quot;&gt;Ghost&lt;/a&gt; platform now for several years now but as I rarely blog I sort of chafe at the hosting cost, especially as this is now the only bit of hosting that is actually costing me. I&#39;ve toyed with the idea of a static site and as there are a number of static site generators out there that support Ghost, I can potentially use these one of generators to push the site to an AWS S3 bucket for &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html&quot;&gt;static web site hosting&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If I do go down this route it would still require me to self-host Ghost so that I can access the admin site when I need to, and here is the rub as these usually cost money. I also wanted the simplest hosting I could find and since I am planning on using a static site generator at some point then the I don&#39;t need anything that is permanently online/available so I looked into what it would take to host Ghost on &lt;a href=&quot;https://www.heroku.com/home&quot;&gt;heroku&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Well it turned it to be simplest thing ever as this is virtually a 1-click &lt;a href=&quot;https://elements.heroku.com/buttons/snathjr/ghost-on-heroku&quot;&gt;deployment&lt;/a&gt; and within minutes I have a Ghost (3.X) blog up and running on heroku. This particular installation defaults to using &lt;a href=&quot;https://cloudinary.com/&quot;&gt;Cloudinary&lt;/a&gt; for image upload storage but we can reconfigure it to use S3 if we decide to. Once heroku had done its thing all I had to do was create the admin account and work out how to migrate the content. Luckily Ghost has an Export/Import content section in the &amp;quot;Labs&amp;quot; which deals with the majority of the blog content, unfortunately it doesn&#39;t have any mechanism to pull the images across so these had to be manually extracted and uploaded again. One thing I noticed was that during the uploading of images, the integration with Cloudinary did some optimisation on the images and the Ghost platform then referenced those optimised images instead; with the originals still available on Cloudinary but now marked with a &lt;code&gt;_o&lt;/code&gt; suffix.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/58964358-1395-414e-b509-23cd73856648/Capture.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Custom themes&lt;/h2&gt;
&lt;p&gt;The default installation comes with a number of built in themes which will work fine however I&#39;ve spent some time customising the Casper theme over the years so that I can have support from disqus (comments) and algolia (search) and I would rather like to keep them. Unfortunately the heroku integration doesn&#39;t allow for persistent saving of an uploaded theme due the ephemeral nature of the heroku filesystem, so as long as the heroku dyno stays up the uploaded theme will still work but as soon as it stops/restarts the uploaded theme is gone and the blog is broken.&lt;/p&gt;
&lt;p&gt;There is however a way forward but it will require that we maintain our own repository with our custom theme(s) installed and push them to heroku. We can also use the method to keep our copy of ghost up to date should we so wish.&lt;/p&gt;
&lt;p&gt;First I download and install the h&lt;a href=&quot;https://devcenter.heroku.com/articles/heroku-command-line&quot;&gt;eroku CLI&lt;/a&gt; and test that the blog still works&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/snathjr/ghost-on-heroku
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ghost-on-heroku

heroku login
heroku git:remote &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; YOURAPPNAME
heroku info

&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push heroku master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had to use the the `--force` switch when pushing but I wasn&#39;t concerned as I knew I could always use the heroku portal to revert back to the last known good deployment should it get messed up.&lt;/p&gt;
&lt;p&gt;Time to add the custom theme&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I removed the following entries from the .gitignore file so I could actually add the theme to the repository.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;content/themes/*
!content/themes/.gitkeep&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. Next I created a folder for our theme in the &lt;code&gt;/content/themes&lt;/code&gt; folder e.g. &lt;code&gt;monkeysee&lt;/code&gt; and then added the changes back to the repository and pushed them to heroku.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Important changes&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push heroku master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the changes are pushed, heroku rebuilt the site and once it was completed we could see the custom theme was available for selection, because the theme is now baked in we are unable to delete it via the admin site.&lt;/p&gt;
&lt;p&gt;The result of this little experiment can be found here &lt;a href=&quot;https://monkey-see-monkey-do-blog.herokuapp.com/&quot;&gt;https://monkey-see-monkey-do-blog.herokuapp.com/&lt;/a&gt; and now allows me to now experiment with the next phase which is introducing a static site generator.&lt;/p&gt;
&lt;p&gt;[Update 18/11/2020] The heroku site is now locked as I have now done the move to only hosting ghost as a headless CMS on Heroku and using Gatsby to generate a static site.&lt;/p&gt;
&lt;p&gt;As always, your feedback is appreciated.&lt;/p&gt;
</description>
      <pubDate>Sat, 04 Jan 2020 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/hosting-ghost-for-free/</guid>
    </item>
    <item>
      <title>What is this &quot;waterfall&quot; thing of which you speak?</title>
      <link>https://blog.many-monkeys.com/posts/what-is-this-waterfall-thing-of-which-you-speak-off/</link>
      <description>&lt;blockquote&gt;
&lt;p&gt;I&#39;m going to describe my personal views about managing large software developments. I have had various assignments during the past nine years, mostly concerned with the development of software packages for spacecraft mission planning, commanding and post-flight analysis. In these assignments I have experienced different degrees of success with respect to arriving at an operational state, on-time, and within costs. I have become prejudiced by my experiences and I am going to relate some of these prejudices in this presentation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;- Winston W. Royce (Managing the development of large software systems)&lt;/p&gt;
&lt;p&gt;The above quote is the start of the paper that to those of us who were taught any form of IT at university in the 80&#39;s and early 90&#39;s (and perhaps later) has become synonymous with the software development life cycle (SDLC) model known as &amp;quot;&lt;a href=&quot;https://en.wikipedia.org/wiki/Waterfall_model&quot;&gt;Waterfall&lt;/a&gt;&amp;quot;; whether this association is correct or not I&#39;ll leave to the historians, or in this case &lt;a href=&quot;https://en.wikipedia.org/wiki/Winston_W._Royce&quot;&gt;Wikipedia&lt;/a&gt;. It does seem to me though that anyone who has actually read the &lt;a href=&quot;http://www-scf.usc.edu/~csci201/lectures/Lecture11/royce1970.pdf&quot;&gt;paper&lt;/a&gt; past page 2, would never make the assertion that a waterfall-like model was something Royce was recommending and what he was describing was actually something rather more familiar to what we try to do today.&lt;/p&gt;
&lt;p&gt;Page 2 of the paper shows the classic waterfall model (or something very similar because Royce never used the term waterfall himself) that I recall having to memorise and recall for an exam.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/983e703c-6163-476e-b744-6197d8134b9b/image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Waterfall SDLC&lt;/p&gt;
&lt;p&gt;By the next few pages the model has gone iterative and by the time you reach the last page, you have the following, which I am going to call Royce&#39;s SDLC.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/1e674553-4cc8-426b-aded-2632151ed615/image1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Royce&#39;s SDLC&lt;/p&gt;
&lt;p&gt;Now, if you are one to read the words and not just look at the pretty pictures you will see references to &amp;quot;Prototyping&amp;quot;, &amp;quot;Testing&amp;quot; and &amp;quot;Involving the Customer&amp;quot; which I personally don&#39;t recall being mentioned during the course and to the current me it also feels a little &amp;quot;agile-y&amp;quot;. There is also a long section on documentation (Step 2) of which Royce has very fond of but then he was also dealing with spaceflight and probably peoples&#39; lives. It is interesting to read that even 40 years ago, developers and documentation didn&#39;t seem to mix well, actually I think it is people and documentation don&#39;t mix and something that we thankfully do less of nowadays and have instead replaced it with living documentation such as wikis and backlogs.&lt;/p&gt;
&lt;h3&gt;Has anyone actually worked on a waterfall project?&lt;/h3&gt;
&lt;p&gt;I also had the chance recently to reflect over my resume, something that was long overdue, and that brought back a lot of memories about the projects I worked on, what practices we used then, and whether I would call those projects waterfall or something else. My first software development roles were at firms where hardware was part of the product and those engineers I worked with definitely iterated over their designs so it felt right to me that we did the same with software. All the big projects were somewhat iterative in nature, new features being added with regular releases. The first time I recall seeing a &amp;quot;big&amp;quot; specification was when I was on a UK government project in 2003-2005 (EU emissions trading, Kyoto protocol) but even then the development team was trying to use agile processes under the hood; not perfectly admittedly, we were just learning to do the agile-walk.&lt;/p&gt;
&lt;p&gt;Some people claim to have done waterfall as I often get to see resumes with &amp;quot;skills: waterfall, agile, ...&amp;quot; etc but I do wonder if waterfall is an actual real-life process or if it is just used as a placeholder for when the SDLC is heavy-process, not-agile. I say a placeholder but I sometimes wonder if it is a straw man or even a bogeyman as it gives a target for those who dislike the not-agile world. I don&#39;t believe I have ever worked on a waterfall project myself, well not one that followed the flow that we would typically attribute to waterfall. I have however been on many-a-project whose process flow would look somewhat like the iterative cascade of Figure 10.  I am still surprised that the waterfall model even came into being is it just feels unnatural and not how I, as a mostly self-taught developer, have ever thought would be a good idea. The cynic in me though feels it is an ideal process for the sort of company where change control and charging for changes is a big part of their operating/revenue model; it could be though that the charging model I am critical of was because of the single direction of the waterfall model and that backing up a step was so expensive.&lt;/p&gt;
&lt;p&gt;As always, your feedback is appreciated.&lt;/p&gt;
</description>
      <pubDate>Mon, 18 Mar 2019 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/what-is-this-waterfall-thing-of-which-you-speak-off/</guid>
    </item>
    <item>
      <title>Debugging NuGet Packages</title>
      <link>https://blog.many-monkeys.com/posts/debugging-nuget-packages/</link>
      <description>&lt;p&gt;Have you ever noticed that now we have embraced the micro-services architecture of doing things, instead of one big monolithic repository of code we have it all broken into smaller repositories of single/reduced responsibility...&lt;/p&gt;
&lt;p&gt;To share these little bits of wisdom we package them up into little parcels that we can import into 100s of other projects distributed across our services. Then, something goes wrong and we can&#39;t debug what is going on inside these little gems and we wonder why we did this and consider if a monolithic repository was all that bad after all.&lt;/p&gt;
&lt;p&gt;Yeah, me too.&lt;/p&gt;
&lt;p&gt;So what can we do about it? Well I&#39;ve picked up a few tricks, forgotten a few, and relearned them again once more. So I am going to note them down now for my future-self.&lt;/p&gt;
&lt;h2&gt;General debugging&lt;/h2&gt;
&lt;p&gt;Before we talk about debugging NuGet packages we need to talk about what we need to actually debug our code and how the debugger uses the various assets we have available to help us do that. The following items are pretty well common for most compiled languages on windows and linux platforms.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Our source-code: this is the stuff we write and where we are going to make changes should we find issues;&lt;/li&gt;
&lt;li&gt;The compiled execution: this is the thing we build and execute, usually an assembly;&lt;/li&gt;
&lt;li&gt;A map-file, this allows us to identify where in our source-code the execution is currently at when debugging.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For .NET this looks like the following&lt;/p&gt;
&lt;p&gt;source-code&lt;/p&gt;
&lt;p&gt;execution&lt;/p&gt;
&lt;p&gt;map-file&lt;/p&gt;
&lt;p&gt;C#, F#, VB.NET, ...&lt;/p&gt;
&lt;p&gt;DLL, EXE&lt;/p&gt;
&lt;p&gt;PDB, MDB&lt;/p&gt;
&lt;p&gt;Now when we are debugging locally we have all these things but when we download a NuGet package it is unusual to find a PDB in the package, probably due to size, and it&#39;s highly unlikely that we&#39;ll see the source code packaged.&lt;/p&gt;
&lt;h2&gt;Debugging NuGet packages&lt;/h2&gt;
&lt;p&gt;If you&#39;re making your own NuGet packages then please consider generating and including the PDB files with your compiled assets. It will make your life so, so much easier because you&#39;ll have better quality stacktraces should an error occur and you can quickly locate where an issue happened, hopefully avoiding the need to debug in the first place.&lt;/p&gt;
&lt;p&gt;Having the location of the errors in your stacktrace saves so much time in identifying where to look for the error from which you can then trace the cause.&lt;/p&gt;
&lt;p&gt;System.InvalidOperationException: L&#39;opération n&#39;est pas valide en raison de l&#39;état actuel de l&#39;objet.
File &amp;quot;C:&#92;projects&#92;opencover&#92;main&#92;OpenCover.Framework&#92;Communication&#92;MessageHandler.cs&amp;quot;, line 113, col 21, in StandardMessage
Int32 StandardMessage(OpenCover.Framework.Communication.MSG_Type, OpenCover.Framework.Manager.IManagedCommunicationBlock, System.Action&lt;code&gt;2[System.Int32,OpenCover.Framework.Manager.IManagedCommunicationBlock], System.Action&lt;/code&gt;1[OpenCover.Framework.Manager.M...
File &amp;quot;C:&#92;projects&#92;opencover&#92;main&#92;OpenCover.Framework&#92;Communication&#92;CommunicationManager.cs&amp;quot;, line 60, col 13, in HandleCommunicationBlock
...&lt;/p&gt;
&lt;p&gt;Before you ask, yes, you can generate PDB files for release builds of your assemblies; also please consider including any intellisense files in your NuGet packages if you have generated them but only if they are suitable for public consumption.&lt;/p&gt;
&lt;p&gt;Even with the PDB files available you are not going to be able to debug very well, if at all, unless you have access to the source code. You may be lucky as you may already have it downloaded (or cloned) or you can pull it from the relevant source control system. Even then you will still need to make sure your source code matches the code base at the time the assembly was built and that can be a little tricky at times as you&#39;ll need to know when it was built and revert your code back to that point in-time.&lt;/p&gt;
&lt;h2&gt;Using ReSharper&lt;/h2&gt;
&lt;p&gt;If you are using .NET and have the right tooling there is a simpler way. When using &lt;a href=&quot;https://visualstudio.microsoft.com/vs/community/&quot;&gt;Visual Studio&lt;/a&gt; with &lt;a href=&quot;https://www.jetbrains.com/resharper/&quot;&gt;ReSharper&lt;/a&gt; it will simply allow you to debug any assembly without source code as long as the PDB file exists. You can either step right into the method you want to investigate and ReSharper will automatically create the source code for you by using the IL and creating equivalent source code. You can also use the &lt;code&gt;Go To Implementation&lt;/code&gt; shortcut (usually Ctrl+F12) and start drilling into the source code of the 3rd party assembly placing breakpoints as you go before you start your debugging run.&lt;/p&gt;
&lt;p&gt;What happens when you don&#39;t have a PDB? Well, you can still use the &lt;code&gt;Go To Implementation&lt;/code&gt; shortcut. However whilst debugging, when you try to create a breakpoint, it will initially fail but if the PDB can be located i.e. in a &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/desktop/debug/symbol-servers-and-symbol-stores&quot;&gt;symbol store&lt;/a&gt;, or it can be generated dynamically, it will prompt you to enable debugging and then you can continue debugging as before; generated PDBs are, by default, placed in &lt;code&gt;%USERPROFILE%&#92;AppData&#92;Local&#92;Temp&#92;SymbolCache&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The one disadvantage of this approach is that the source code you are debugging is not your actual source code but it is a close representation of what it could be i.e. source code that when compiled should produce the same &lt;a href=&quot;https://en.wikipedia.org/wiki/Common_Intermediate_Language&quot;&gt;IL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also understand not everyone can afford ReSharper but all is not lost because the above functionality is also available as part of &lt;a href=&quot;https://www.jetbrains.com/decompiler/&quot;&gt;DotPeek&lt;/a&gt; which is free.&lt;/p&gt;
&lt;h2&gt;Is there another way?&lt;/h2&gt;
&lt;p&gt;There does appear to be a solution on the horizon (still in Beta at the time of writing but has strong support) that will allow debugging of packages and it is called &lt;a href=&quot;https://github.com/dotnet/sourcelink&quot;&gt;&amp;quot;Source Link&amp;quot;&lt;/a&gt;, it can be used with most git repositories such as GitHub, Bitbucket and Azure Devops etc and what it does is add a special link into your nuget package to your git repository along with the appropriate &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Git-Objects&quot;&gt;SHA&lt;/a&gt;, with this information and a supporting debugger (i.e. Visual Studio) can pull the appropriate source code resources. As I said it is still beta but if you are okay to update all your packages going forward then this is probably the future.&lt;/p&gt;
&lt;p&gt;Over time I can see that the latest packages on NuGet will start to use this method as it makes sense in that it resolves the issue of stepping through the actual code rather than a close representation and by using the SHA it focuses on the files as they were at the time. Here is a &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/library-guidance/sourcelink&quot;&gt;demo&lt;/a&gt; of Source Link being used in &lt;a href=&quot;https://www.newtonsoft.com/json&quot;&gt;Newtonsoft.Json&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What if I have no access to the source code?&lt;/h2&gt;
&lt;p&gt;You can still create a PDB for your assembly using tools that come with Visual Studio and you can access from your developer command prompt e.g.&lt;/p&gt;
&lt;p&gt;ildasm /out=target_assembly_source.il target_assembly.dll
ilasm target_assembly_source.il /dll /pdb&lt;/p&gt;
&lt;p&gt;Once you have your new DLL and associated PDB you will now need to recompile using the newly rebuilt assembly, then you&#39;ll be able to step into the code, you will be stepping though the generated IL code though, this isn&#39;t perfect though and &lt;a href=&quot;http://encyclopedia2.thefreedictionary.com/Your+Mileage+May+Vary&quot;&gt;YMMV&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/b04fa217-c326-4f93-bb0a-6bd4b57d5068/DebugIL.png&quot; alt=&quot;DebugIL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As always, your feedback is appreciated.&lt;/p&gt;
</description>
      <pubDate>Sat, 16 Feb 2019 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/debugging-nuget-packages/</guid>
    </item>
    <item>
      <title>Adding a tags page to a Ghost blog</title>
      <link>https://blog.many-monkeys.com/posts/adding-a-tags-page-to-ghost-blog/</link>
      <description>&lt;p&gt;An odd thing about Ghost is though it allows you to tag your posts it doesn&#39;t provide an out-of-the-box way to access all the tags as a single view.&lt;/p&gt;
&lt;p&gt;It is relatively easy to set one up yourself and give it a reasonably consistent look and feel to the main blog.&lt;/p&gt;
&lt;p&gt;To start you need to enable the host public API, you&#39;ll find this in the &lt;em&gt;Labs&lt;/em&gt; section of your ghost admin. Then, you need to create a static page with a post url of &lt;em&gt;tags&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/628549c8-0cf9-441a-acad-b6087824ea4c/tagsghost.png&quot; alt=&quot;tags-ghost&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now we have to create a special theme file called &lt;code&gt;page-tags.hbs&lt;/code&gt; for that &lt;em&gt;tags&lt;/em&gt; page. This page will be used to render content for this post instead of the default &lt;code&gt;post.hbs&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-handlebars&quot;&gt;&lt;code class=&quot;language-handlebars&quot;&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{{!&amp;lt; default}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{{!-- The big featured header, it uses blog cover image as a BG if available --}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#post&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;header&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site-header outer &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;feature_image&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;feature_image&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;no-cover&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/if&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;inner&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;site-nav&quot;&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site-header-content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{{!-- The main content area --}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site-main&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site-main outer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
&lt;span class=&quot;token selector&quot;&gt;.inner-page-tags&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inherit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 900px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;.inner-page-tags&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -8vw&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;inner inner-page-tags&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-feed&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#get&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;tags&#39;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;all&#39;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;count.posts&#39;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;count.posts desc&#39;&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#foreach&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;{{!-- The tag below includes the markup for each tag - partials/tag-card.hbs --}}&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tag-card&quot;&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/foreach&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/get&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/post&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the partials folder create another theme file called &lt;code&gt;tag-card.hbs&lt;/code&gt;, this file will be used to render each tag card so that it has a similar look and feel to the posts when viewed as a collection.&lt;/p&gt;
&lt;pre class=&quot;language-handlebars&quot;&gt;&lt;code class=&quot;language-handlebars&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-card &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;post_class&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#unless&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;feature_image&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; no-image&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/unless&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;#if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;feature_image&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-card-image-link&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-card-image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;feature_image&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token block keyword&quot;&gt;/if&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-card-content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-card-content-link&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;header&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-card-header&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-card-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post-card-excerpt&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;A collection of &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;plural&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;posts&#39;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;singular&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;% post&#39;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;plural&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;% posts&#39;&lt;/span&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally add a link to your blog navigation so your visitors can find this new handy page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/3cbe05c8-6aad-4b72-91b6-b97e70d1d883/tag2.png&quot; alt=&quot;tag2&quot; /&gt;&lt;/p&gt;
</description>
      <pubDate>Mon, 11 Feb 2019 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/adding-a-tags-page-to-ghost-blog/</guid>
    </item>
    <item>
      <title>Not dead yet...</title>
      <link>https://blog.many-monkeys.com/posts/not-dead-yet/</link>
      <description>&lt;p&gt;So it has been a while but I am glad to finally say I have released another version of OpenCover - 4.7.922.&lt;/p&gt;
&lt;p&gt;The release candidate has been out for a few weeks now with no issues reported so I decided to bite the bullet and get the latest release out; the releases, as always, can be found on &lt;a href=&quot;https://www.nuget.org/packages/OpenCover/&quot;&gt;Nuget&lt;/a&gt;, &lt;a href=&quot;https://chocolatey.org/packages/OpenCover/4.7.922&quot;&gt;Chocolatey&lt;/a&gt; and &lt;a href=&quot;https://github.com/OpenCover/opencover/releases/tag/4.7.922&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;d say most of the major issues were addressed and OpenCover should have better support for assemblies built using .net core thanks to the wonderful &lt;a href=&quot;https://github.com/jbevain/cecil&quot;&gt;Mono.Cecil&lt;/a&gt; library. I&#39;ve also hooked in &lt;a href=&quot;https://sentry.io/&quot;&gt;Sentry&lt;/a&gt; to collect crash reports, we used to use &lt;a href=&quot;https://drdump.com/crash-reporting-system&quot;&gt;DrDump&lt;/a&gt; with 4.6.519 but I feel that Sentry will help us be more proactive in identifying and fixing any issues. If you do have any problems then please raise them on &lt;a href=&quot;https://github.com/OpenCover/opencover/issues&quot;&gt;issues page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are a few defects/issues that I&#39;ll probably have a go at in the next few weeks/months but I can&#39;t see any major features being added in the near future, I will however look at and accept any pull-requests that adds value to the project so feel free to dive in.&lt;/p&gt;
&lt;p&gt;I also recently found out that &lt;a href=&quot;https://www.ndepend.com/&quot;&gt;NDepend&lt;/a&gt; is also supporting OpenCover coverage files now, so that is a big win to the community that have been asking for that capability over the years.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NDepend v2019.1 has been released with support for VisualStudio solution analysis, support for OpenCover and VS coverage binary format, 9 new security rule and more &lt;a href=&quot;https://t.co/5cjhEHJgqz&quot;&gt;https://t.co/5cjhEHJgqz&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/ndepend?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#ndepend&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/opencover?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#opencover&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/visualstudio?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#visualstudio&lt;/a&gt; #2019 &lt;a href=&quot;https://t.co/SEiPmza2Ha&quot;&gt;pic.twitter.com/SEiPmza2Ha&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;— ndepend (@ndepend) &lt;a href=&quot;https://twitter.com/ndepend/status/1090929622303342592?ref_src=twsrc%5Etfw&quot;&gt;January 31, 2019&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As always your feedback is appreciated.&lt;/p&gt;
</description>
      <pubDate>Sun, 10 Feb 2019 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/not-dead-yet/</guid>
    </item>
    <item>
      <title>A spike on `robust` JSON handling in .NET</title>
      <link>https://blog.many-monkeys.com/posts/introducing-hale-net/</link>
      <description>&lt;p&gt;When working with JSON formatted data in .NET I have always found it frustrating that I am losing something valuable if I want to use some form of contract to help reason about the code and improve understanding about the entities being worked upon.&lt;/p&gt;
&lt;h6&gt;What did I just receive?&lt;/h6&gt;
&lt;p&gt;The first issue I often come across is that after I have deserialized the data I simply can&#39;t tell the difference between &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt; (or missing/absent) e.g. if we had the following entity&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;User&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; Name &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;&lt;/span&gt; Age &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then if we deserialized either of the following JSON objects into it&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;Name&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Arthur Dent&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;Age&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or,&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;Name&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Arthur Dent&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then in both cases, after deserialization, &lt;code&gt;Age&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;. Should we wish to serialize that entity we can either serialize &lt;code&gt;Age&lt;/code&gt; as &lt;code&gt;null&lt;/code&gt; or we can omit it, but, we can&#39;t do both i.e. we can never be 100% sure we are creating the same representation that was received and we could be adding or losing information that may have a detrimental effect on a downstream system that consumes the data.&lt;/p&gt;
&lt;h6&gt;I don&#39;t know about you yet!&lt;/h6&gt;
&lt;p&gt;Another issue I often encounter is if the JSON object received has more information than expected e.g.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;Name&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Arthur Dent&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;Age&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;Address&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ZZ9 Plural Z Alpha&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we deserialize and serialize again, then we will now lose the &lt;code&gt;Address&lt;/code&gt; field and this is something we probably want to avoid.&lt;/p&gt;
&lt;p&gt;In all these cases, there are ways to handle them but I find them tedious to implement and it probably leaves an ungodly mess behind for someone else to pick up.&lt;/p&gt;
&lt;h5&gt;Coupling of services&lt;/h5&gt;
&lt;p&gt;In the last example, where an unknown field is potentially lost, this is often solved by ensuring all services have the same contract. When you add/remove fields from a contract we often use a shared package or file and this leads to laborious upgrading of each service or client that uses that contact and then we have to deal with the subsequent deployment and synchronization issues that then ensue. This just feels wrong as we should be developing (micro)services that can be independently deployed but now we have created a dependency between these services and have effectively created a &lt;a href=&quot;https://www.infoq.com/news/2016/02/services-distributed-monolith&quot;&gt;distributed monolith&lt;/a&gt;. This problem is probably better explained in this Channel 9 talk &amp;quot;&lt;a href=&quot;https://channel9.msdn.com/Blogs/Subscribe/DataContract-Coupling-in-Messaging&quot;&gt;Data/Contract Coupling in Messaging&lt;/a&gt;&amp;quot;.&lt;/p&gt;
&lt;h6&gt;Robustness Principle&lt;/h6&gt;
&lt;p&gt;We have better things to do with our time. What I needed was a way to take a typed contract e.g. using an interface that describes the entities I want to work with, that I can deserialize JSON objects into but be tolerant of what it reads whilst preserving the original JSON structure unless I have actually modified it; this sounds similar to the robustness principle.&lt;/p&gt;
&lt;p&gt;The Robustness Principle is also known as &lt;a href=&quot;https://en.wikipedia.org/wiki/Robustness_principle&quot;&gt;Postel&#39;s Law&lt;/a&gt; and simply states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Be conservative in what you do, be liberal in what you accept from others&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the world of services (and now micro-services I suppose) this is sometimes referred to as the &lt;a href=&quot;https://martinfowler.com/bliki/TolerantReader.html&quot;&gt;Tolerant Reader&lt;/a&gt; where we need to be tolerant of what we read so that our contracts can simply evolve without holding us back.&lt;/p&gt;
&lt;h4&gt;Introducing Hale.NET&lt;/h4&gt;
&lt;p&gt;Now there was no way I am going to be able to create a better &lt;a href=&quot;https://www.nuget.org/packages/Newtonsoft.Json&quot;&gt;Json.NET&lt;/a&gt; library for this purpose but I can use it to do the heavy lifting when handling JSON. I also feel I should try some &lt;a href=&quot;https://en.wikipedia.org/wiki/Aspect-oriented_programming&quot;&gt;AOP&lt;/a&gt; techniques such as interceptors (e.g. &lt;a href=&quot;http://www.castleproject.org/projects/dynamicproxy/&quot;&gt;Castle Windsor Dynamic Proxy&lt;/a&gt;) or weaving (e.g. &lt;a href=&quot;https://github.com/Fody/Fody&quot;&gt;Fody&lt;/a&gt;) to remove some of the repetitiveness.&lt;/p&gt;
&lt;h5&gt;The spike&lt;/h5&gt;
&lt;p&gt;Since my spike is showing potential and that other people have expressed an interest I thought it would be better to share now rather than just tinker myself when time permits. The spike (definitely not production ready) can be found on &lt;a href=&quot;https://github.com/sawilde/hale.net&quot;&gt;Github&lt;/a&gt; and I have released it under the MIT licence. It currently only handles the most basic of object structures (no arrays or hierarchies) but it does&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;preserve the underlying data by using a &lt;code&gt;JObject&lt;/code&gt; and an interceptor to handle the &lt;code&gt;get_&lt;/code&gt; and &lt;code&gt;set_&lt;/code&gt; of our properties.&lt;/li&gt;
&lt;li&gt;has some basic handling for dealing with &lt;code&gt;null&lt;/code&gt; vs &lt;code&gt;undefined&lt;/code&gt; using exceptions and some extension methods.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;Assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetValueOrDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;u &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; u&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Age&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsReferenced&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;u &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; u&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Age&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Next steps&lt;/h5&gt;
&lt;p&gt;The next step is to handle hierarchies of objects and arrays because without the ability to do this, it is not going to be of any use whatsoever.&lt;/p&gt;
</description>
      <pubDate>Tue, 20 Feb 2018 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/introducing-hale-net/</guid>
    </item>
    <item>
      <title>A weekend at Random Hacks of Kindness</title>
      <link>https://blog.many-monkeys.com/posts/random-hack-of-kindness/</link>
      <description>&lt;p&gt;&lt;a href=&quot;http://www.rhokaustralia.org/#rhok-home&quot;&gt;Random Hacks of Kindness&lt;/a&gt; (or RHoK for short) is a hacking event that I&#39;ve been involved with on and off over the past four or five years. Since we have just had a recent RHoK event in Melbourne (Nov 2017) I thought I should write down what my own personal involvement was this time so that others may get a feel of what it is like to become involved in RHoK or other similar hacking events.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/1d5a5871-1b14-4b72-8da7-3c52fdf2783f/randomhacks.png&quot; alt=&quot;randomhacks&quot; /&gt;&lt;/p&gt;
&lt;p&gt;RHoK is not a competitive hacking event with big prizes up for grabs but instead aims to be a collaborative hacking event where some of the hackers will switch teams when they cease to be of use to their current team or feel they can provide more value on another team. Rather than trying to use some company&#39;s new API and do something cool with it we instead look at trying to solve real-world problems for the &lt;a href=&quot;http://www.rhokaustralia.org/peeps/changemakers&quot;&gt;changemakers&lt;/a&gt; who usually come from a charity, community group or social-enterprise and who have a real-world problem that they would like help with i.e. usually idea-rich, cash-poor looking for a kick-start. Another feature of RHoK, is the emphasis on continuing involvement in the same project between RHoK events through what has become known as RHolls (Rock &#39;n&#39; Roll - get it?) that take place every 4-6 weeks; and even using your own spare time if you have any to spare. There is no actual commitment to be involved with a project after a hack event has finished but it is really encouraged and it is up to each individual to decide on their continuing level of involvement.&lt;/p&gt;
&lt;p&gt;So who gets involved in RHoK? Well, it isn&#39;t just software developers or coders as these projects require people with a wide range of skills and backgrounds so that we can be effective and deliver the right thing. My friend Samara tweeted this picture&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is why you don’t put the computer scientist on hack weekend registration duty &lt;a href=&quot;https://twitter.com/rhokmelb?ref_src=twsrc%5Etfw&quot;&gt;@rhokmelb&lt;/a&gt; 😉RHoKstar traits (v1.0) &lt;a href=&quot;https://twitter.com/hashtag/hackathon?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#hackathon&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/rhoksummer?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#rhoksummer&lt;/a&gt; &lt;a href=&quot;https://t.co/3NIwdTBwu3&quot;&gt;pic.twitter.com/3NIwdTBwu3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;— Samara (@EvilAngelPixie) &lt;a href=&quot;https://twitter.com/EvilAngelPixie/status/934743513979273216?ref_src=twsrc%5Etfw&quot;&gt;November 26, 2017&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;The hack weekend&lt;/h3&gt;
&lt;p&gt;Now that the stage has been set I&#39;ll continue to describe my involvement with the most recent Melbourne RHoK event.&lt;/p&gt;
&lt;h4&gt;Day 1.&lt;/h4&gt;
&lt;h6&gt;The Changemaker Pitches&lt;/h6&gt;
&lt;p&gt;This was the final chance for each of worthy changemakers to make their cause known and to persuade any final non-committed hackers to join their team. In no particular order (mainly because I forgot) the changemakers on the day were.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.berrystreet.org.au/&quot;&gt;Berry Street&lt;/a&gt; - Berry Street are back with their mission to help children in protection stay connected to their families and other important people in their lives. This changemaker, like several changemakers before them, are proof that you can get a team to engage in several RHoK and RHoLL events to get that project across the line.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gojanegive.org/&quot;&gt;Go Jane Give&lt;/a&gt; - Hoping that RHoK can help them extend the reach of the grassroots campaign that allows you to turn your talents and interests into a fundraiser for your favourite causes.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://carerscouch.com.au/&quot;&gt;Carers Couch&lt;/a&gt; - Needs help to provide online support to carers of people with cancer. Martina of Carers Couch has introduced a new term &amp;quot;cabbage salad&amp;quot; that we are sure is to replace the word &amp;quot;spaghetti&amp;quot; when dealing with awful/complex code.&lt;/li&gt;
&lt;li&gt;PollyannR - Wants to improve the way that regional creatives can get the funding they need.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.startbroadband.com.au/&quot;&gt;Start Broadband&lt;/a&gt; - Helping disadvantaged Aussie families get online.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.shifra.io/&quot;&gt;Shifra&lt;/a&gt; - Looking to use technology to increase/improve sexual and reproductive health resources for mobile populations, such as refugees.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.caretocompare.com.au/&quot;&gt;Care to Compare&lt;/a&gt; - An enterprise where consumers will get to compare and choose health products with 100% of the profits going to charity.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.hitnet.com.au/&quot;&gt;Hitnet&lt;/a&gt; - Co-creates and distributes health information and services to marginalised communities. They need help in maintaining and managing the content for their 70+ (and growing) information hubs that are provided to local communities across the country.&lt;/li&gt;
&lt;/ul&gt;
&lt;h6&gt;Team forming and storming&lt;/h6&gt;
&lt;p&gt;Hackers who had already been to the information night held earlier in the month had already picked their cause and started to form around the respective changemakers, others quickly joined the teams that they felt they could contribute to. I joined up with Carers Couch as I had some previous interaction with them on the run-up to the hack event as I was asked to be their RHoK mentor and to help them prepare for the weekend. The team started off by introducing themselves and getting down to the task of determining what the needs were and what could be tackled in that weekend. As the team was large enough that there was even a possibility that several tasks could be tackled in the same weekend.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/5a474b8e-4cb8-4161-853e-1c3433e786eb/DPb53i3VAAAe9qm.jpg&quot; alt=&quot;The Carers Couch team&quot; /&gt;&lt;/p&gt;
&lt;p&gt;During this time another RHoK mentor came over and asked if we had any UI/UX people willing to jump ship to help another team that really needed one. Once we had a lull in our session I went over to the Hitnet team to get more details about what they needed and it looked they had already found a UI person and had now picked their goldilocks problem (not too big or too small, just right) and were stuck with another issue involving XML. After a quick discussion I realised I could probably contribute more to this team rather than to the initial Carers Couch team I was currently involved in, and so after a quick apology to the team, I moved tables.&lt;/p&gt;
&lt;p&gt;After another round of introductions, we started to carve up the problem into a potential solution and assign some tasks to ourselves.&lt;/p&gt;
&lt;h6&gt;The problem&lt;/h6&gt;
&lt;p&gt;Dan Laush has written a wonderful &lt;a href=&quot;https://medium.com/@dan.laush/people-focus-in-order-to-scale-rhok-melbourne-summer-2017-d19d8ca78d6e&quot;&gt;write-up&lt;/a&gt; of the project itself so I&#39;ll only summarise here.&lt;/p&gt;
&lt;p&gt;The Hitnet team need to update an XML configuration file for each hub on their network to control what content is to be displayed on each and they currently do this by hand for over 70+ hubs each time new content is supplied to them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/d4b1ee32-b73c-4a5d-8e3e-2321ab798cba/ScreenShot20171126at21102PM1.png&quot; alt=&quot;A sample XML hub file - well the part we need to manipulate&quot; /&gt;&lt;/p&gt;
&lt;h6&gt;The approach&lt;/h6&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/2ed290d3-2966-4b50-8be6-5f4d999dd78f/20171126_164145c.jpg&quot; alt=&quot;A strawman design&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The team identified we had just the right skills to split into three to tackle each part of the intended solution of our simple multi-tier architecture. As I had already decided to jump onto this team to help them tackle the XML issue I decided to concentrate on the worker process that would take XML files that were used for hub configuration and update them based on data pulled from an API that was to be built by other members of the team. By breaking up the project this way kept the concerns separate and allowed individual teams to largely work independently of each other, mocking the data where required until the other team(s) were ready to serve us our data.&lt;/p&gt;
&lt;h6&gt;The worker process&lt;/h6&gt;
&lt;p&gt;Hitnet were already using Google Cloud Platform (GCP) to host their servers and so it seemed only right that we put the worker there right next to the servers/files it will need to interact with. An added bonus is that I had never used GCP before so now was a chance for a learning experience as well; a big plus in my opinion.&lt;/p&gt;
&lt;p&gt;The worker process had the task of taking an XML configuration file for a hub and updating it with data retrieved from an API call. The data itself was the description of the modules, i.e. content, that are to be displayed on that hub. We quickly fleshed out a number of tasks needed to meet the objectives and check if the worker was a feasible choice.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How easy is it to create a Function on GCP?&lt;/li&gt;
&lt;li&gt;How do we read and write files from/to storage?&lt;/li&gt;
&lt;li&gt;How will we manipulate the XML files?&lt;/li&gt;
&lt;li&gt;How will we make the API calls?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Assumptions&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;As we did not have direct access to Hitnet&#39;s GCP account (and since we are new to this it is right we should be kept well away) we made the assumption that the XML files were available via a GCP storage bucket.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Creating a Function on GCP is really easy and in minutes, I had created an account and got access to $300 of free credits to use over the next year. &lt;a href=&quot;https://nodejs.org/en/&quot;&gt;Node.js&lt;/a&gt; appears to be the default language for writing Functions on GCP and Google has also provided a number of &lt;a href=&quot;https://cloud.google.com/functions/docs/tutorials/&quot;&gt;examples&lt;/a&gt;; these examples had pretty well answered how to do steps (1) and (2) which was a win. The worker process itself is triggered by a simple HTTP(s) request and it seems it could also be triggered by a message placed on a queue but we have no need for that at the moment. There was no mechanism for a timed trigger like with have with Azure Functions but we could use a &lt;a href=&quot;https://cloud.google.com/solutions/reliable-task-scheduling-compute-engine&quot;&gt;cron job&lt;/a&gt; or a service like Zapier.&lt;/p&gt;
&lt;p&gt;Manipulating the XML, proved to be harder than it should have been and I eventually settled on using the &lt;a href=&quot;https://www.npmjs.com/package/xml2js&quot;&gt;xml2js&lt;/a&gt; NPM package as it used the &lt;a href=&quot;https://www.npmjs.com/package/xmlbuilder&quot;&gt;xmlbuilder&lt;/a&gt; NPM package that would allow us to save the manipulated data back to XML again. We finally got to the stage where we had the ability to pull, manipulate and push back a single XML file. Finished the day by adding code to iterate each file in the target storage bucket and update them.&lt;/p&gt;
&lt;h6&gt;End of the day&lt;/h6&gt;
&lt;p&gt;At the end of the day, each member of the Hitnet team had something successful to declare:
UI team - had a React app up and running and created their first forms.
API team - had spun up an API using nginx and a Postgres database.
Worker team - had a worker process that could do all the parts required for it.&lt;/p&gt;
&lt;h4&gt;Day 2.&lt;/h4&gt;
&lt;h6&gt;Coming in by train&lt;/h6&gt;
&lt;p&gt;I had a look at the code I helped create the day before whilst heading back to the event and after all the hacking and tweaking the day before it was a mix of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Callback_function&quot;&gt;callbacks&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;promises&lt;/a&gt; and it felt dirty. However, this is not a difficult thing to resolve and so I used the time to clean up the code.&lt;/p&gt;
&lt;h6&gt;Putting it all together&lt;/h6&gt;
&lt;p&gt;After the success of the day before we were all ready to connect everything up and this really put the pressure on the API team to create the APIs we needed. Whilst I waited for the API team to create the many endpoints needed by the front-end team I spent some time adding some error handling, improving the detail of the console logging and, generally tidying up the code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/c7a3099b-0339-4d68-a73a-88930bd202f2/DPg8NLiVoAAEye7c.jpg&quot; alt=&quot;The Hitnet team&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once the API team were ready for me, we worked together to build the query that returns the required content modules for each hub. To consume the API I decided to use the &lt;a href=&quot;https://www.npmjs.com/package/node-fetch&quot;&gt;node-fetch&lt;/a&gt; NPM package to make the API call and, because I dislike building URLs using string concatenation is this always seems to cause problems for someone later down the line, I decided to construct any URLs using the &lt;a href=&quot;https://www.npmjs.com/package/url-assembler&quot;&gt;url-assembler&lt;/a&gt; NPM package.&lt;/p&gt;
&lt;h6&gt;The marketplace&lt;/h6&gt;
&lt;p&gt;At previous RHoK events we stopped at 3pm for presentations held in a lecture theatre but this year the organisers decided to use &amp;quot;The Marketplace&amp;quot;. During the time allocated each team can spend time presenting and demoing to the other hackers and the judges and hopefully persuade those with remaining tokens to vote for them for the People&#39;s Choice awards (and yes you could vote for yourself if you wanted to but I don&#39;t know of anyone that did).&lt;/p&gt;
&lt;h4&gt;The future&lt;/h4&gt;
&lt;p&gt;There are still things to do with this function to make it production ready and we hope to deal with these in the next few weeks through the RHoll events that we have already booked up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security - we need some, not only to make sure only trusted users can use the new UI but to also make sure the API is not called incorrectly and to finally ensure the worker is not constantly triggered and use up our precious credits on GCP.&lt;/li&gt;
&lt;li&gt;Integration - we need to integrate with Hitnet&#39;s GCP and see if we can access their files via the cloud storage that we &lt;a href=&quot;https://cloud.google.com/compute/docs/disks/gcs-buckets&quot;&gt;assumed we could&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Process - improve the build, test, deployment process of the worker function. We are looking to hand this back to Hitnet at a later date so they can maintain this going forward.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Summary&lt;/h4&gt;
&lt;p&gt;I definitely enjoyed the weekend and I definitely learnt something new, even better when it is doing something that would be of actual value to someone. The code for the worker (like everything produced at RHoK) can be found on their github account i.e. &lt;a href=&quot;https://github.com/RHoKAustralia/hitnet-worker&quot;&gt;hitnet-worker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I believe everyone in the team tried/learnt something new, I saw this tweet from Liz who also joined the Hitnet team to work with Dan on the front-end.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Finally had a crack at building a usable React app at &lt;a href=&quot;https://twitter.com/rhokmelb?ref_src=twsrc%5Etfw&quot;&gt;@rhokmelb&lt;/a&gt; for &lt;a href=&quot;https://twitter.com/HITnet_au?ref_src=twsrc%5Etfw&quot;&gt;@HITnet_au&lt;/a&gt;. Also put on my UX/designer hat for it. So happy with what our team achieved! 😊 &lt;a href=&quot;https://t.co/CJc0O7JTUD&quot;&gt;pic.twitter.com/CJc0O7JTUD&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;— Lizarrrrgh (´･ω･`) (@lnoogn) &lt;a href=&quot;https://twitter.com/lnoogn/status/934693948517269505?ref_src=twsrc%5Etfw&quot;&gt;November 26, 2017&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and my understanding is that Ankit and Peter, who made up the API team, were also in somewhat personally unexplored territory when building the API using nginx and Postgres.&lt;/p&gt;
</description>
      <pubDate>Mon, 04 Dec 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/random-hack-of-kindness/</guid>
    </item>
    <item>
      <title>Can you give something back?</title>
      <link>https://blog.many-monkeys.com/posts/open-source-needs-you/</link>
      <description>&lt;p&gt;Why does it seem, to me at least, that the vast body of developers will actively use software that has been contributed through open source efforts but will do nothing to add to that wealth and instead continue to rely on the efforts of others? How can we try to change that behaviour and get more developers contributing in some way?&lt;/p&gt;
&lt;p&gt;I wrote about a &lt;a href=&quot;https://monkey-see-monkey-do-blog.herokuapp.com/how_do_we_get_users_out_of_opensource_welfare_/&quot;&gt;similar topic&lt;/a&gt; some years ago and I referred to it as a type of welfare. Perhaps it was a bit harsh because it tends to infer that these developers are taking advantage of those contributing, whereas instead they are just enjoying the fruits of what those people have contributed and, more importantly, freely given for such purposes. In a way it is a bit like art in the public gallery/domain, in that once the code/software has been written and released freely, anyone can use it without diminishing the pleasure of it for someone else.&lt;/p&gt;
&lt;p&gt;So why do some developers not contribute? I&#39;ve tried to come up with some reasons I think may be the case, based on conversations I have had, and added my responses.&lt;/p&gt;
&lt;h6&gt;It&#39;s all about the money!&lt;/h6&gt;
&lt;p&gt;&lt;em&gt;You believe that these projects make millions as suggested by this cartoon and you don&#39;t want to give your valuable time for free so someone else can make money?&lt;/em&gt;
&lt;img src=&quot;https://ucarecdn.com/63325d1f-4e70-4efe-ab6a-57fde21c6281/ME_439_OpenSource.png&quot; alt=&quot;ME_439_OpenSource&quot; /&gt;&lt;a href=&quot;https://commons.wikimedia.org/wiki/File:ME_439_OpenSource.png&quot;&gt;https://commons.wikimedia.org/wiki/File:ME_439_OpenSource.png&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is something to consider I suppose and there are some projects where a number of service companies have spun up around supporting the project/product in the commercial space but these projects are rare when considered against the number of open source projects out there, well known perhaps, but still rare.
Though we should consider that when we use an open source projects in our own code we are saving millions for ourselves and our employers and clients and that is nearly as good as making millions. According to the open hub network the popular &lt;a href=&quot;https://www.nuget.org/packages/Newtonsoft.Json/&quot;&gt;Json.NET package&lt;/a&gt; has taken 33 person years of effort with an estimated &lt;a href=&quot;https://www.openhub.net/p/JsonNET/estimated_cost&quot;&gt;cost of $1.8m&lt;/a&gt;. I personally believe the cost is much higher.&lt;/p&gt;
&lt;h6&gt;Where do I start?&lt;/h6&gt;
&lt;p&gt;&lt;em&gt;You do not know where to start or even if your contribution would be accepted?&lt;/em&gt; I suppose it can be a little scary but also a little exciting as well when you submit that first pull request, most projects have guidelines that help any new contributers to a project and it is unlikely that a submission is rejected outright. It maybe be pushed back a bit due to things like testing or coding style but that is all part of the learning process and the things that we do every day when we join new teams. There are a few initiatives out there that aim to get beginners involved in contributing to open source projects e.g. &lt;a href=&quot;http://www.firsttimersonly.com/&quot;&gt;first timers only&lt;/a&gt; and though there are not many issues using &lt;a href=&quot;https://github.com/search?q=label%3Afirst-timers-only&amp;amp;state=open&amp;amp;type=Issues&quot;&gt;the &#39;first-timers-only&#39; tag&lt;/a&gt; at the moment, it is a start.&lt;/p&gt;
&lt;p&gt;I first started to contribute to projects that solve, or nearly solve, my own issues (I would say that is still where the majority of my own efforts go) and just dived in and gave it a go; if I didn&#39;t fix it, well, who was to know except my own ego.&lt;/p&gt;
&lt;h6&gt;Will my bosses let me?&lt;/h6&gt;
&lt;p&gt;&lt;em&gt;You are unsure about your legal obligations when to comes to contributions to open source projects?&lt;/em&gt; This is a tough one and right now I am going to use that irritating phrase that people use when they are about to talk something legal, I am not a lawyer (IANAL) but...&lt;/p&gt;
&lt;p&gt;If you have an employment contract read it over and look for relevant clauses - a lot of these contracts have clauses from a bygone era and just haven&#39;t changed to keep up with the time, talk it over with your bosses explain them the benefits of contributing e.g.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fixing an issue that affects your day to day work and would in turn make you more effective or the software you are developing for them better.&lt;/li&gt;
&lt;li&gt;Personal and professional development by working on software and concepts that are not normally part of your day to day work, improving those skills will have a beneficial impact on your work.&lt;/li&gt;
&lt;li&gt;You&#39;ll work on it in your own time, though you may need to get permission to use company resources e.g. laptop/software. You should try to get an agreement about when you use company time vs personal time i.e. if the issue you are addressing is directly related to work then you can use company time, treat it as part of the project and encourage others to contribute.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As long as you are not contributing to a open source product that rivals your company&#39;s business, most employers I&#39;d have thought, will agree to some level of contribution - some more pro-arguments for contributing can found in this &lt;a href=&quot;https://blog.codeship.com/why-your-employees-should-be-contributing-to-open-source/&quot;&gt;blog article&lt;/a&gt;.&lt;/p&gt;
&lt;h6&gt;What about my rights?&lt;/h6&gt;
&lt;p&gt;Some projects have a &lt;a href=&quot;https://gist.github.com/sawilde/4820db0a6151a1144a0c&quot;&gt;Community Licence Agreement&lt;/a&gt; for contributions and these agreements are more about protecting the project and making sure that your contribution can be used without restriction for both the project and for yourself. Open source projects often don&#39;t have the dollars to fight any legal battles and so this way these projects protect themselves from any predatory legal action. It is highly unlikely you will be divulging any trade secrets through any contribution you make and it would/should be pretty obvious to yourself if you are treading the thin line. Just like when you use an open source project, or pull a package from nuget, you should look at the licence that comes with it to make sure that you usage complies with your business activities, again IANAL so you may want to have it checked out if you are unsure.&lt;/p&gt;
&lt;h6&gt;I just don&#39;t have the time!&lt;/h6&gt;
&lt;p&gt;And this is probably the main crux of it all, it is tough finding time to learn outside of work especially with family obligations and keeping up with those social connections that we do, contrary to popular opinion regarding software engineers, actually have.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So this is my &lt;strong&gt;big&lt;/strong&gt; ask, if you use open source projects in your work or personal projects all I want from you 4 hours a month.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/42e85dcc-0b03-4efc-b72a-de402afac7ba/1ozetn.jpg&quot; alt=&quot;1ozetn&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Yes, less than 1 hour a week on average is all I am asking of you to try and contribute, hopefully you are doing more than this anyway for personal development and improving your &lt;em&gt;craft&lt;/em&gt;. Perhaps integrate it as part of that development; want to learn a new programming language and hate just working through code samples? Find a project and just pitch in, it&#39;ll probably more fun and rewarding than just following trite &lt;a href=&quot;http://wiki.c2.com/?HelloWorldInManyProgrammingLanguages&quot;&gt;&amp;quot;hello world&amp;quot; examples&lt;/a&gt;.
Also, though not an argument you may want to use with your employers, it is useful to show your contributions to prospective future employers as it demonstrates a willingness to learn and grow that go far beyond the stock &amp;quot;I have a Pluralsight subscription&amp;quot; (as good as it is by the way but along as long as you actually use it) responses during interviews. Not all of us have website portfolios to demonstrate our capability and it goes far beyond the code challenges that we are often presented with as we move from role to role, so consider it an investment in the future you.&lt;/p&gt;
&lt;p&gt;As always your thoughts are appreciated.&lt;/p&gt;
</description>
      <pubDate>Wed, 17 May 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/open-source-needs-you/</guid>
    </item>
    <item>
      <title>Aw shucks, thank you!</title>
      <link>https://blog.many-monkeys.com/posts/aw-shucks-thankyou/</link>
      <description>&lt;p&gt;I just received this today and it really made my day and I thought I should share.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hiya Shaun,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Just wanted to drop a quick email of emphatic thanks for your many years of work with OpenCover. I was tasked with the job just recently of introducing unit + service tests, along with things to ensure quality outcomes are being achieved with this (i.e., measurable outputs)... OpenCover was such a simple drop-in tool.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Having never used it, I was up and going in under 2 hrs, complete with HTML reports, and a wrapping cmd file so it&#39;s about as idiot proof as I can get things.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;So... no reason to this email other than to make sure you know at least someone appreciates your hard work :-)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Hope life is treating you well!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/9a7e85ac-bee0-48f0-a5c5-bac8194765d2/0519986c195c198779774fd25e111030fe728bwm2.jpg&quot; alt=&quot;0519986c195c198779774fd25e111030fe728b-wm-2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As I said that really made my day, I am glad that someone has found our work on OpenCover useful and not just at places I/we happen to &lt;a href=&quot;https://blog.many-monkeys.com/happy_birthday_open_cover/&quot;&gt;work at&lt;/a&gt;. I must also give a &lt;a href=&quot;https://www.urbandictionary.com/define.php?term=shout-out&quot;&gt;shout out&lt;/a&gt; to the other other &lt;a href=&quot;https://github.com/OpenCover/opencover/graphs/contributors&quot;&gt;contributors&lt;/a&gt; of this project over the years and give a big thanks to Daniel who wrote the &lt;a href=&quot;https://github.com/danielpalme/ReportGenerator&quot;&gt;reporting generator&lt;/a&gt; tool that makes the output from OpenCover look so good.&lt;/p&gt;
</description>
      <pubDate>Thu, 20 Apr 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/aw-shucks-thankyou/</guid>
    </item>
    <item>
      <title>The importance of canary builds.</title>
      <link>https://blog.many-monkeys.com/posts/the-importance-of-canary-builds/</link>
      <description>&lt;p&gt;So now that &lt;a href=&quot;https://www.visualstudio.com/downloads/&quot;&gt;Visual Studio 2017&lt;/a&gt; is officially out I thought I would use the long Easter weekend to upgrade the OpenCover project to this new version and tackle any issues that I normally encounter when this upgrade time comes around. However before I can start this upgrade process I first need to tackle the bit rot that has recently set in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bit rot (or &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_rot&quot;&gt;software rot&lt;/a&gt;) is when your code just starts failing due to lack of maintenance or a change in the build or execution environment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Fortunately I have a weekly canary build that I previously set-up that amongst other things will alert me when this happens (as well as inform me if I get any new &lt;a href=&quot;https://blog.many-monkeys.com/improving-your-source-code/&quot;&gt;code quality&lt;/a&gt; issues), it started &lt;a href=&quot;https://ci.appveyor.com/project/sawilde/opencover/build/4.6.648&quot;&gt;bleating&lt;/a&gt;,
or should that be tweeting, a few weeks back so I knew I had some issues to rectify but not the actual severity. So in the space of a few months (I decided to stop work on OpenCover over the summer as I needed a break and time to look at other technologies) the following things happened:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AppVeyor upgraded its Visual Studio 2015 image to use a release version of .NET Core. This caused a number of issues that I couldn&#39;t repeat on my local build environment so I have temporarily resolved the issue by uninstalling it for my server builds.&lt;/li&gt;
&lt;li&gt;The local and server builds don&#39;t build the same flavour of the .NET Core application so I needed to update the tests to take that into account; I intend to look into this more after completing the upgrade.&lt;/li&gt;
&lt;li&gt;Badges were failing and so the landing page was looking a bit &lt;a href=&quot;https://www.urbandictionary.com/define.php?term=daggy&quot;&gt;daggy&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The build was failing and was not reporting it properly, this was easy to resolve and I was surprised it had escaped unnoticed for all this time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If it wasn&#39;t for the regular weekly build I would not have been aware of some of these issues and makes me glad that I configured that build to trigger regardless of whether I or anyone else had submitted code to the repository. Now that I have a working (and hopefully more reliable) build again, I am now ready to tackle the upgrade and more than likely I will have to &lt;a href=&quot;https://blog.many-monkeys.com/death-by-a-thousand-cuts/&quot;&gt;update the tooling&lt;/a&gt; again.&lt;/p&gt;
&lt;p&gt;Title Image: Getty, CC-BY&lt;/p&gt;
</description>
      <pubDate>Fri, 14 Apr 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/the-importance-of-canary-builds/</guid>
    </item>
    <item>
      <title>Keep your development workspace tidy</title>
      <link>https://blog.many-monkeys.com/posts/keep-your-development-workspace-tidy/</link>
      <description>&lt;p&gt;A big issue I find when working in today&#39;s modern development environment is the ever increasing number of git repositories we now have to maintain.&lt;/p&gt;
&lt;p&gt;With each repository comes a number of branches that we create, push and pull as we progress the development of each service and over time they just start to build up like driftwood on a beach; not the pretty driftwood of photos and art-pieces but junk useless wood that have long served their purpose. Just recently I counted that in the space of a couple of months I had pulled in over 40 repositories and most of those repositories had multiple branches and in one extreme case I had over 30 branches, all of the branches had either been merged back to master or I had abandoned e.g. spikes.&lt;/p&gt;
&lt;p&gt;Now I could have done the simplest thing and just removed each one individually as I went along or just devote sometime every so often and do the same but en-masse. Instead I decided to do neither and instead I wrote a script that I could execute from a bash shell and later refined it into an alias.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;bfg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;for d in */; { echo $d; cd $d; { git checkout -q master; git branch | egrep -v &quot;(^&#92;*)|(^&#92;s+(master|dev|hotfix|qa))&quot; | xargs --no-run-if-empty git branch -D ; }; cd ..; };&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I call it &lt;a href=&quot;https://en.wikipedia.org/wiki/BFG_(weapon)&quot;&gt;BFG&lt;/a&gt; because it shows no mercy and I only run it when I just want to tidyblow things up.&lt;/p&gt;
&lt;p&gt;Let me describe how it works (and I am doing this as much for my sake as for yours.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For each subfolder under the current folder&lt;/li&gt;
&lt;li&gt;switch to the master branch
e.g. &lt;code&gt;git checkout -q master&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;list all the available branches
e.g. &lt;code&gt;git branch ...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;filter out those in the &#39;keep&#39; list
e.g. &lt;code&gt;... | egrep -v &amp;quot;(^&#92;*)|(^&#92;s+(master|dev|hotfix|qa))&amp;quot; ...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;if any extra branches found delete them
e.g. &lt;code&gt;... | xargs --no-run-if-empty git branch -D ;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I now try to run this at least once a month, especially when we have delivered on a number of features, and I know that it is safe to do so. If I am feeling nervous about running the script I substitute the &lt;code&gt;-D&lt;/code&gt; for &lt;code&gt;-d&lt;/code&gt; when executing &lt;code&gt;git branch&lt;/code&gt; as this will not remove a branch if it has not yet been merged with its upstream.&lt;/p&gt;
&lt;p&gt;Any questions or suggestions for improvements please post below.&lt;/p&gt;
</description>
      <pubDate>Sat, 01 Apr 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/keep-your-development-workspace-tidy/</guid>
    </item>
    <item>
      <title>Adding search to your [ghost] blog - part 2</title>
      <link>https://blog.many-monkeys.com/posts/adding-search-to-your-ghost-blog-part-2/</link>
      <description>&lt;p&gt;Okay this is the next step in adding search functionality to my blog.&lt;/p&gt;
&lt;p&gt;The biggest let down of the original integration was that I need to remember to run the search updater every time I made a new, or just updated a, blog post, but what if I was writing the entry remotely or, more than likely, just plain forgot?
At the end of the &lt;a href=&quot;https://blog.many-monkeys.com/adding-search-to-your-ghost-blog-2/&quot;&gt;last post&lt;/a&gt; I mentioned the possibility of adding a IFTTT snippet (actually they call them applets) to automate the process, so whilst the idea was still fresh I decided to investigate the idea.
Unfortunately I could not find a way for IFTTT to execute a node script when my blog changed but I could use it to send a web request to another service which could then execute a script when it received that request. For this second service I decided to use Azure functions because well I have some spare free credit per month and I might as well use it for something useful.&lt;/p&gt;
&lt;h6&gt;Setting up the Azure function&lt;/h6&gt;
&lt;p&gt;Creating an Azure function is relatively easy (assuming you have an account) but if you decide to use another service, e.g. AWS Lambda, then the below may provide hints about how you may implement similar functionality.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you don&#39;t already have one, create a &amp;quot;Function App&amp;quot; (Compute).&lt;/li&gt;
&lt;li&gt;Once created, Create a simple app that uses Javascript (node) and could be triggered by an API.
[I also chose to set the authorization level as Function as I prefer some level of access-control.]&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/aa8b5688-ac12-4915-9b41-7af3a86a02e0/function.png&quot; alt=&quot;function&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We need to pull in the &lt;code&gt;algolia-webcrawler&lt;/code&gt; package, to do so upload the &lt;code&gt;package.json&lt;/code&gt; file below and run &lt;code&gt;npm install&lt;/code&gt; from the Console. [I upload all the files into the same folder as the function I am creating. I also find the &lt;a href=&quot;https://blogs.msdn.microsoft.com/benjaminperkins/2014/03/24/using-kudu-with-windows-azure-web-sites/&quot;&gt;Kudu console&lt;/a&gt; works best for this as it displays the output/progress of the command.]&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rss-ghost-algoliasearch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token string-property property&quot;&gt;&quot;algolia-webcrawler&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^1.0.3&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Next, upload your configured &lt;a href=&quot;https://github.com/DeuxHuitHuit/algolia-webcrawler/blob/master/config.json&quot;&gt;config.json&lt;/a&gt; file that is used to control the &lt;code&gt;algolia-webcrawler&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now, replace the &lt;code&gt;index.js&lt;/code&gt; file with the following snippet. [I did play about a bit here and finally decided that &lt;code&gt;spawn&lt;/code&gt; was the method that worked best for me.]&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; exec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;child_process&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;spawn&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;HTTP trigger function processed a request.&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  child &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;node&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;__dirname &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/node_modules/algolia-webcrawler&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&#39;--config&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
__dirname &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/config.json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stdout&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stderr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  child&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;close&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[END] code&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  res &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// status: 200, /* Defaults to 200 */&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Finally, run the application to test that it works. [You can see the output in the Logs section.]&lt;/li&gt;
&lt;/ul&gt;
&lt;h6&gt;Setting up IFTTT&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;Goto IFTTT and create a New Applet&lt;/li&gt;
&lt;li&gt;For the &amp;quot;IF&amp;quot; choose RSS (new feed item) and enter the URL to the rss feed of the blog e.g. &lt;a href=&quot;http://blog.many-monkeys.com/rss/&quot;&gt;http://blog.many-monkeys.com/rss/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For the &amp;quot;THAT&amp;quot; choose Maker WebHooks and enter the url to the function e.g. &lt;a href=&quot;https://functions-many-monkeys.azurewebsites.net/api/UpdateBlogSearchIndex?code=K2mp&quot;&gt;https://functions-many-monkeys.azurewebsites.net/api/UpdateBlogSearchIndex?code=K2mp&lt;/a&gt;...&lt;/li&gt;
&lt;li&gt;Test the trigger works - this may take some time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Assuming everything above works without issue, then whenever your blog updates the IFTTT applet will be triggered, usually within an hour - docs say 15 mins) and the search index on Algolia updated.&lt;/p&gt;
&lt;h6&gt;Using Zapier&lt;/h6&gt;
&lt;p&gt;I am not sure what is going on with IFTTT but I found I couldn&#39;t rely on it to run when I updated my posts so I tried a similar service called &lt;a href=&quot;https://zapier.com/&quot;&gt;Zapier&lt;/a&gt; instead. Creating a zap is just as easy as creating an applet, RSS-&amp;gt;WebHook, and the free plan also states 5 (or 15 mins according to the free plan) between checks.&lt;/p&gt;
&lt;p&gt;To make Zapier work though I had to use the option &amp;quot;anything is different&amp;quot; for the RSS trigger, so the issue with IFTTT may be related to how Ghost generates the RSS feed that is being consumed by the trigger.&lt;/p&gt;
&lt;p&gt;I would appreciate any feedback and suggestions for further improvements.&lt;/p&gt;
</description>
      <pubDate>Mon, 27 Mar 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/adding-search-to-your-ghost-blog-part-2/</guid>
    </item>
    <item>
      <title>Adding search to your [ghost] blog</title>
      <link>https://blog.many-monkeys.com/posts/adding-search-to-your-ghost-blog-part-1/</link>
      <description>&lt;p&gt;Recently I wanted to find something in my own blog that I had written about and though I only have a small number of posts compared to some, it still took more time than it really should have.&lt;/p&gt;
&lt;p&gt;So I decided to look at adding some search functionality; because I am originally from Yorkshire it should be free, because I am lazy it should be relatively easy. A quick google search (the meta-irony is not lost on me) and a few dead ends, I ended up trying &lt;a href=&quot;https://www.algolia.com/&quot;&gt;Algolia&lt;/a&gt;. Now this looks like it is a really powerful search tool and I am nowhere near going to be using it to its fullest potential for this blog but the &lt;a href=&quot;https://www.algolia.com/demos&quot;&gt;demos&lt;/a&gt; I have seen look amazing.&lt;/p&gt;
&lt;p&gt;Now it was so simple to get going I thought I should share what I did to actually integrate it to my site (and so add to the myriad of other tutorials on the subject). First you&#39;ve probably already seen the search on the main index page but if not this is what it looks like&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/d31629dc-143a-478a-baa5-eba843dca42c/search1.png&quot; alt=&quot;search1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;and when searching&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/5775e17a-7130-4c0e-9fd1-98c4fb4f05dc/search2.png&quot; alt=&quot;search2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;okay it&#39;s not the prettiest set of results at the moment however it is functional and I can tweak it later.&lt;/p&gt;
&lt;h6&gt;Getting Started&lt;/h6&gt;
&lt;p&gt;Once signed up and goingskipping through the tutorial you arrive at a dashboard where you can create an application and choose a region. It is explained and if your user-base is largely based in a single region then this is really useful but otherwise I was a little confused so I just choose the place nearest to where the blog is hosted, which is probably the same region.&lt;/p&gt;
&lt;p&gt;Once the application was created I was stuck (did I mention there was a tutorial?), I expected to find an &amp;quot;index this site&amp;quot; button or feature but it seems Algolia is API based and no such options existed for mere mortals like me.&lt;/p&gt;
&lt;h6&gt;Loading the search index&lt;/h6&gt;
&lt;p&gt;Another quick investigation and I came across an npm package named &lt;a href=&quot;https://www.npmjs.com/package/algolia-webcrawler&quot;&gt;algolia-webcrawler&lt;/a&gt; which can be given a sitemap.xml and crawl the site/blog based on its contents. I took the sample &lt;a href=&quot;https://github.com/DeuxHuitHuit/algolia-webcrawler/blob/master/config.json&quot;&gt;config.json&lt;/a&gt; and modified it up to look a bit like so.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;blog.many-monkeys.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;cred&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;appid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;&amp;lt;app-id-goes-here&gt;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;apikey&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;&amp;lt;admin-api-key-goes-here&gt;&gt;&quot;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;oldentries&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;86400000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;siteIndex&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;settings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token string-property property&quot;&gt;&quot;attributesToIndex&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unordered(description)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unordered(text)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;token string-property property&quot;&gt;&quot;attributesForFaceting&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lang&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;sitemaps&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://blog.many-monkeys.com/sitemap.xml&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;lang&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://blog.many-monkeys.com/sitemap-posts.xml&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;lang&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;http&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;auth&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;selectors&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;meta[property=&#92;&quot;og:image&#92;&quot;]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;meta[name=&#92;&quot;description&#92;&quot;]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;h1, h2, h3, h4, h5, h6, p, li&quot;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;formatters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token string-property property&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-&quot;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;defaults&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;blacklist&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;

	&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For some reason, that I obviously haven&#39;t yet investigated, it didn&#39;t work with just the main &lt;code&gt;sitemap.xml&lt;/code&gt; and so I added the additional &lt;code&gt;sitemap-*.xml&lt;/code&gt; files that I thought were valuable at this stage. Once the crawler was executed with the above config, I found that I had an index that I could use for searching my blog.&lt;/p&gt;
&lt;h6&gt;Adding search to the blog&lt;/h6&gt;
&lt;p&gt;I did find another &lt;a href=&quot;https://blog.lorentzca.me/install-algolia-search-on-ghost/&quot;&gt;tutorial&lt;/a&gt; about adding Algolia to a Ghost blog but it was in Japanese and Google translate didn&#39;t help me much but it did have a plain HTML snippet at the bottom that I shamelessly took and chopped up as necessary to use with my blog; these changes can be seen in this &lt;a href=&quot;https://github.com/sawilde/Casper/commit/4c4e6983c9d8e6daefb9bb5af9fa7ed44f40af0f&quot;&gt;commit&lt;/a&gt; on GitHub.&lt;/p&gt;
&lt;p&gt;The example didn&#39;t work out of the box as-is for me but it also didn&#39;t take long to get it running with a bit of debugging and tweaking.&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code class=&quot;language-markup&quot;&gt;{{!-- The main content area on the homepage --}}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;placeholder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Search posts&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;search-input&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

  {{!-- The tag below includes the post loop - partials/loop.hbs --}}
  {{&gt; &quot;loop&quot;}}

  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cdn.jsdelivr.net/autocomplete.js/0/autocomplete.min.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;algoliasearch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;&amp;lt;app-id-goes-here&gt;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;&amp;lt;search-api-key-goes-here&gt;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;siteIndex&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;autocomplete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#search-input&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;hint&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; autocomplete&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sources&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hits&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;hitsPerPage&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;templates&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;suggestion&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;suggestion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; suggestion&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_highlightResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;suggestion&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;autocomplete:selected&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; suggestion&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dataset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;suggestion&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dataset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;Pros&lt;/h6&gt;
&lt;ol&gt;
&lt;li&gt;It works and is free, okay you have to drop the Algolia image on your site somewhere (I kept it in the search box where it made sense) but nothing really comes for free and it isn&#39;t that intrusive.&lt;/li&gt;
&lt;li&gt;Easy to setup and integrate, writing this post took longer than installing the search functionality.&lt;/li&gt;
&lt;li&gt;Multiple indexes - I can see these becoming useful if I start to tweak my integration so as to try different things out during development without affecting the current live-integration.&lt;/li&gt;
&lt;li&gt;There appears to be a strong &lt;a href=&quot;https://community.algolia.com/&quot;&gt;community&lt;/a&gt; to get plenty of help/support; in fact the snippet I used above looks like it may have initially come from here.&lt;/li&gt;
&lt;/ol&gt;
&lt;h6&gt;Cons&lt;/h6&gt;
&lt;ol&gt;
&lt;li&gt;Could be simpler to get started with a built in webcrawler of some form from the dashboard itself - there could be some standard usage scenarios for blogs (they have a &lt;a href=&quot;https://community.algolia.com/docsearch/&quot;&gt;documentation indexer&lt;/a&gt; already so perhaps they are heading down that path).&lt;/li&gt;
&lt;li&gt;You have to run the webcrawler manually each time you publish a new post to the blog, though perhaps a &lt;a href=&quot;https://ifttt.com/&quot;&gt;IFTTT&lt;/a&gt; snippet might be possible using the generated RSS feed, a post for another day perhaps.&lt;/li&gt;
&lt;/ol&gt;
</description>
      <pubDate>Sat, 25 Mar 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/adding-search-to-your-ghost-blog-part-1/</guid>
    </item>
    <item>
      <title>It&#39;s astounding, time is fleeting, madness takes its toll, ...</title>
      <link>https://blog.many-monkeys.com/posts/its-astounding-time-is-fleeting-madness-takes-its-toll/</link>
      <description>&lt;p&gt;Okay, starting a blog post using a title from the first lines of the lyrics to &amp;quot;The Time Warp&amp;quot; does seem a bit unusual but with what I intend to cover in this it will all make sense, probably.&lt;/p&gt;
&lt;p&gt;Time... what is it really? I am not going into some weird arty-pseudo-psycho babble of the &lt;a href=&quot;http://www.mindfullyalive.com/blog/2015/6/7/massive-art-installation-on-the-ephemeral-nature-of-time&quot;&gt;ephemeral nature of time&lt;/a&gt; but as a software developer I usually have to deal with time, and dates, in some form everyday and I find myself having the same conversations with other developers about how to handle date and time in specific scenarios. What I have found is that even though we, as people, use time every day in our lives we really don&#39;t always understand it and even when we feel we have a grasp we often have to remind ourselves about what we are doing. Even now when someone refers to something like &amp;quot;midnight on the 20th&amp;quot;, I have to query &amp;quot;Do you mean the midnight between the 19th and 20th or the 20th and 21st?&amp;quot;; people &lt;a href=&quot;http://english.stackexchange.com/questions/6459/how-should-midnight-on-be-interpreted&quot;&gt;usually mean the latter&lt;/a&gt; but for computers it is always the former. Now, the observant amongst you may have noticed that I started off with &#39;time&#39; but now I have started to use the terms &#39;date and time&#39; together and that is very deliberate as time on its own is pretty useless for most cases without the date and together they create the &lt;em&gt;when&lt;/em&gt;. And now I am going to add a third term to the mix and this is &lt;em&gt;where&lt;/em&gt; because date and time we observe in the real-world is also dependant on where you are and I think anyone reading this will have experienced this at some point.&lt;/p&gt;
&lt;h4&gt;My rules&lt;/h4&gt;
&lt;p&gt;I am not going to say my grasp on the subject is perfect, as obvious from above, and to help developers like myself there are some wonderful libraries that really take the grunt work out of the handling of date and time but even with these tools we can still mess it up because we forget about what it is we are trying to handle. Personally, when it comes to development I have a few simple rules that pretty well cover 99% of all cases that I have to deal with when handling date and time that I would like to share.&lt;/p&gt;
&lt;h5&gt;Rule 1: If in doubt, make sure you use UTC...&lt;/h5&gt;
&lt;p&gt;... and make it someone else&#39;s problem to convert it; this is pretty well my default position on most occasions when I need to deal with time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;UTC stands for &lt;a href=&quot;https://www.timeanddate.com/worldclock/timezone/utc&quot;&gt;Coordinated Universal Time&lt;/a&gt; and if you are confused about about the abbreviation well it was apparently chosen so that it &lt;a href=&quot;https://www.timeanddate.com/time/utc-abbreviation.html&quot;&gt;does not favour any one language&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But regardless of the abbreviation employed it is an awesome thing for us developers as it gives us a common baseline that can be utilised by the languages we use in our daily development; it is unlikely that you will find a modern language that does not support some way of getting the current date and time in UTC e.g.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now&quot;&gt;JavaScript&lt;/a&gt;: var when = Date.now();&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/system.datetime.utcnow(v=vs.110).aspx&quot;&gt;.NET&lt;/a&gt;: var when = DateTime.UtcNow;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;UTC is great for logging and auditing purposes, and really anytime we want to store a time-stamp against a specific piece of data or an event. Even better for computers, as long as they are correctly sync&#39;d to a time server, then the UTC time you will get on each computer will be the same (I am ignoring things like clock-drift etc for this article but I acknowledge its existence and the issues it can cause). Finally UTC isn&#39;t affected by DST and so you don&#39;t get odd behaviour due to time when this local time change occurs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;DST stands for &lt;a href=&quot;https://www.timeanddate.com/time/dst/&quot;&gt;Daylight Savings Time&lt;/a&gt; and its application around the world is rather arbitrary with &lt;a href=&quot;https://en.wikipedia.org/wiki/Daylight_saving_time&quot;&gt;some countries adopting it&lt;/a&gt;, others ignoring and some using it, applying it all year round, abandoning it. And in some cases like Australia it depends on the &lt;a href=&quot;http://www.australia.gov.au/about-australia/facts-and-figures/time-zones-and-daylight-saving#Daylightsaving&quot;&gt;state&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;UTC is also great for storing past events because, the past doesn&#39;t change and so converting it to local time for a viewer is always predictable; this is where those libraries really come in useful as they can also take care of that oft-forgotten DST offset that sometimes needs to be applied as well as the users timezone (the &lt;em&gt;when&lt;/em&gt; and the &lt;em&gt;where&lt;/em&gt; aspects) when you need to present the time of the event back to the user.&lt;/p&gt;
&lt;h6&gt;Learn to read time&lt;/h6&gt;
&lt;p&gt;Most languages support the basics of dealing with dates and time but it is also good to make sure you also understand how to interpret some common time representations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;2017-02-05 05:00:00&amp;quot; - 5am on 5th February 2017, however there is no timezone information and so will, more often than not, be interpreted as local time by most languages.&lt;/li&gt;
&lt;li&gt;&amp;quot;2017-02-05 05:00:00Z&amp;quot; - 5am on 5th February 2017 UTC, the &lt;em&gt;Z&lt;/em&gt; indicates what is known as &lt;a href=&quot;https://www.timeanddate.com/worldclock/timezone/zulu&quot;&gt;Zulu&lt;/a&gt; time and is another, usually military/aviation, term for UTC.&lt;/li&gt;
&lt;li&gt;&amp;quot;2017-02-05 05:00:00+00:00&amp;quot; - is also 5am on 5th February 2017 UTC, this time we have provided the offset in hours and minutes from UTC that the time represents.&lt;/li&gt;
&lt;li&gt;&amp;quot;2017-02-05 05:00:00+11:00&amp;quot; - is also 5am on 5th February 2017 but this time in a timezone that is currently 11 hours ahead of UTC; this is equivalent to &amp;quot;2017-02-04 18:00:00+00:00&amp;quot;.&lt;/li&gt;
&lt;li&gt;&amp;quot;2017-02-05 05:00:00-07:00&amp;quot; - is also 5am on 5th February 2017, in a timezone that is currently 7 hours behind UTC; this is equivalent to &amp;quot;2017-02-05 12:00:00+00:00&amp;quot;.&lt;/li&gt;
&lt;li&gt;&amp;quot;2017-02-05T05:00:00+1100&amp;quot; - is also 5am on 5th February 2017, in a timezone that is currently 11 hours ahead of UTC; this is a common representation often seen, a T is used to separate the date and time and the offset is still hours and minutes but they are sometimes not separated by a colon (:); in this case however if the the offset is missing then assume UTC(*).&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;(*) “Your &amp;quot;common representation often seen&amp;quot; is &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601&lt;/a&gt;. This is the universal standard. A pox on all those framework designers who bastardised it slightly because reasons...”&lt;/p&gt;
&lt;p&gt;- I Shepherd&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://xkcd.com/1179/&quot;&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/iso_8601.png&quot; alt=&quot;ISO 8601&quot; title=&quot;ISO 8601 was published on 06/05/88 and most recently amended on 12/01/04.&quot; /&gt;https://xkcd.com/1179/&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you do see a time stamp with an offset e.g. +11:00 or -07:00, then to convert it back to UTC you subtract the hours and minutes from the time presented, as shown in the above examples; please note that you should treat the +/- sign as you would in any addition operation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h6&gt;Learn to write and parse time&lt;/h6&gt;
&lt;p&gt;Though reading time seems pretty straightforward for us humans, for computers it can be quite tricky because us humans are not sensible/consistent and some libraries don&#39;t default the way you would think they would e.g. &lt;code&gt;01/02/2017&lt;/code&gt; is this Jan 2nd or Feb 1st, depending on where you are from will probably determine what you say; if you are US American then you will probably go with the former but the rest of the world will more likely go with the latter (exceptions apply). But what about computer libraries what will they do?&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Wed Feb 01 2017&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;2017/2/1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Mon Jan 02 2017&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;1/2/2017&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Invalid Date&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;13/2/2017&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So we see that default parsing in JavaScript will assume that if you put a year first then it will be followed by month and then date but it will assume US American format if you put the year at the end. So my rule of thumb here is to always format dates as year/month/day and if I have to parse a date format that I didn&#39;t write myself to ask about the format used because you may need to work just a little bit harder when you parse it.&lt;/p&gt;
&lt;h5&gt;Rule 2: For real-life events, store the timezone...&lt;/h5&gt;
&lt;p&gt;... of &lt;em&gt;where&lt;/em&gt; the event is expected to take place. This will then allow you to convert the stored time to another local time in another timezone. This is really important for events that are to happen in the future because the future is fluid and it is not unknown for some countries to change when they may trigger daylight savings with extremely short notice but if you keep your computer patched with the updates then you should be okay i.e. if you are on a Microsoft OS then &lt;a href=&quot;https://support.microsoft.com/en-au/kb/914387&quot;&gt;KB914387&lt;/a&gt; is the one to keep any eye on; you may find it quiet interesting to see what changes have happened around the world.&lt;/p&gt;
&lt;p&gt;Now you may have noticed that I haven&#39;t said anything about whether the date and time of the event should be stored in UTC or local time and that is because it depends on your scenario.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1 - TV Schedule.&lt;/strong&gt; The &amp;quot;Local News at 6pm&amp;quot; will, more often than not, be scheduled at 6pm and this will happen day after day regardless of the DST in effect, even if DST usage was suddenly changed. In this scenario storing the local date and time along with the timezone is probably fine. The same would apply for any sort of events that stop and start in the same location e.g. meetings, restaurant bookings etc. You may even find that the timezone is largely unused if the event is just physical but if there is any electronic sharing of the booking to persons or systems outside the location then it is usually important to maintain the timezone component.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2 - Travel.&lt;/strong&gt; Events like travel where the start time and end time could possibly be in different times zones e.g. Air travel, then storing the date and time in UTC along with the timezone(s) will probably be the best approach. The complexity involved in planning flights etc would not adapt quickly to a sudden change in DST usage and so the people affected may just find that the local time of the flight has changed but not as it relates to the rest of the world.&lt;/p&gt;
&lt;h6&gt;Which timezone list?&lt;/h6&gt;
&lt;p&gt;When storing your timezone try to store and use a library that will let you use the timezone list from the &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_tz_database_time_zones&quot;&gt;tz database&lt;/a&gt;, this list usually breaks a timezone into a region and place e.g. Europe/London or Australia/Melbourne, and tends to have more cross adoption between languages than other, usually &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/gg154758.aspx&quot;&gt;OS specific&lt;/a&gt;, lists.&lt;/p&gt;
&lt;p&gt;This list is also more granular and deal with the oddballs of the world e.g. in Australia for instance we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NSW (+10:00), VIC (+10:00), SA (+09:30), ACT (+10:00) and TAS (+10:00) all of which use DST but QLD (+10:00), NT (+9:30) and WA (+08:00) currently do not.&lt;/li&gt;
&lt;li&gt;a town called Broken Hill (&lt;a href=&quot;https://en.wikipedia.org/wiki/Yancowinna_County&quot;&gt;Yancowinna&lt;/a&gt;) that is in NSW (+10:00) but instead shares the same timezone as SA (+09:30) aka &amp;quot;Australia/Broken_Hill&amp;quot;.&lt;/li&gt;
&lt;li&gt;a town in WA (+08:00) called &lt;a href=&quot;https://en.wikipedia.org/wiki/Eucla,_Western_Australia&quot;&gt;Eucla&lt;/a&gt; (+08:45) which is in a timezone that has a +45 minutes offset to the rest of the state aka &amp;quot;Australia/Eucla&amp;quot;.&lt;/li&gt;
&lt;li&gt;and (finally) and island off NSW (+10:00) call &lt;a href=&quot;https://en.wikipedia.org/wiki/Lord_Howe_Island&quot;&gt;Lord Howe Island&lt;/a&gt; (+10:30) that utilises a +30 minute DST during summer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&#39;s not just the wildlife that makes Australia just one strange place.&lt;/p&gt;
&lt;h6&gt;Libraries&lt;/h6&gt;
&lt;p&gt;There are many libraries out there for your chosen language that will help you handle time especially if your chosen language has limited support. I&#39;ll only list ones that I have used recently that have done the job asked of them (and support the above timezone list) rather than discuss the merits of each library.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.NET: &lt;a href=&quot;http://blog.nodatime.org/&quot;&gt;NodaTime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JavaScript: &lt;a href=&quot;https://momentjs.com/&quot;&gt;moment.js&lt;/a&gt; and &lt;a href=&quot;https://momentjs.com/timezone/&quot;&gt;moment-timezone.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Rule 3: Avoid using &amp;quot;Local Now&amp;quot;...&lt;/h5&gt;
&lt;p&gt;... and instead use &amp;quot;UTC Now&amp;quot; whenever possible, especially when processing 2 or more times. &amp;quot;Local Now&amp;quot; is subject to the computer settings the code it is executed on and when the wrong &amp;quot;now&amp;quot; is used the defects are really subtle and may not be easily repeatable on a developers machine.
If you are in&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Europe/Africa&lt;/strong&gt;: then the odds you will not notice the issues during your working day but your users may report odd things happening late at night.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;North/South America&lt;/strong&gt;: if anything is going to occur it will probably be during the afternoon when the weird stuff happens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asia/Australia&lt;/strong&gt;: the system will probably have odd behaviour during the morning.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The issues usually arise because developers have their machines running in local time but it is not unusual nowadays for servers in the cloud to be running UTC (with no DST applied) and so if a developer uses &amp;quot;Local Now&amp;quot; they should really use &amp;quot;UTC Now&amp;quot; and convert it to the actual timezone. Personally I would ban any local now usage from my code base and I would like that Microsoft make methods/functions like &lt;code&gt;DateTime.Now&lt;/code&gt; obsolete.&lt;/p&gt;
&lt;h6&gt;Testing&lt;/h6&gt;
&lt;p&gt;Testing your time manipulations and conversions can be very tricky especially if you use the System API to get the current time in your tests. If you can, try and mock out the usage of such APIs; some libraries such as NodaTime supply one for you, with JavaScript something like &lt;a href=&quot;http://sinonjs.org/&quot;&gt;Sinon.JS&lt;/a&gt; may be your best bet. You may also find it worthwhile that when you run your tests that you change the timezone of you development environment occasionally and check that your tests continue to work regardless of the timezone of the computer running the tests. You may also find that you need to check your test data with an external system so I recommend the &lt;a href=&quot;https://www.timeanddate.com/worldclock/meeting.html&quot;&gt;meeting planner&lt;/a&gt; on &lt;a href=&quot;http://www.timeanddate.com/&quot;&gt;http://www.timeanddate.com&lt;/a&gt; as it allows you to enter your own times and see the results for multiple locations.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/654bdc89-bd46-4610-b538-90a1310bbfbf/Capturetime.png&quot; alt=&quot;Capture-time&quot; /&gt;&lt;/p&gt;
&lt;h6&gt;...finally&lt;/h6&gt;
&lt;p&gt;These are the rules I try to abide by but rules can be broken sometimes and there will always be special cases.&lt;/p&gt;
&lt;p&gt;If you have further suggestions about what has worked for you that you would care to share, or see or believe that I have made a grave error in my thinking then please comment below, I am always willing to discuss and learn.&lt;/p&gt;
&lt;h6&gt;Other Resources&lt;/h6&gt;
&lt;p&gt;&lt;a href=&quot;http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time&quot;&gt;Falsehoods programmers believe about time&lt;/a&gt; - &lt;a href=&quot;http://infiniteundo.com/&quot;&gt;Infinite Undo!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/2292334/difference-between-utc-and-gmt-standard-time-in-net&quot;&gt;GMT Standard Time - A Gotcha&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Sat, 21 Jan 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/its-astounding-time-is-fleeting-madness-takes-its-toll/</guid>
    </item>
    <item>
      <title>Configuring Cloudflare Page Rules</title>
      <link>https://blog.many-monkeys.com/posts/configuring-cloudflare-page-rules/</link>
      <description>&lt;p&gt;I moved to &lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;Cloudflare&lt;/a&gt; sometime ago so that I could take advantage of their tools such as free DNS, SSL, analytics, caching etc. to support my &lt;a href=&quot;https://ghost.org/&quot;&gt;ghost&lt;/a&gt; based blog.&lt;/p&gt;
&lt;p&gt;I wanted to host my blog on &lt;a href=&quot;https://blog.many-monkeys.com/&quot;&gt;https://blog.many-monkeys.com&lt;/a&gt; but I didn&#39;t want to host &lt;a href=&quot;http://www.many-monkeys.com/&quot;&gt;http://www.many-monkeys.com&lt;/a&gt; nor &lt;a href=&quot;http://many-monkeys.com/&quot;&gt;http://many-monkeys.com&lt;/a&gt; anywhere and wanted to keep my options open i.e. if I wanted to use the domain for more than just a blog.&lt;/p&gt;
&lt;p&gt;I still wanted to support &lt;a href=&quot;https://www/&quot;&gt;https://www&lt;/a&gt;... as there are a number of old links out there that point to my old site/blog but I didn&#39;t want to pay hosting for a single page that would redirect someone to the blog page. When I read up on this I found some DNS providers have a URL record which is used to configure this sort of behaviour. However I couldn&#39;t find out how to configure this sort of record in Cloudflare and so I remained stuck on the single page hosting solution.&lt;/p&gt;
&lt;p&gt;The other day I was clicking around the Cloudflare site and I stumbled on the Page Rules and after a bit of trial an error I got it to behave the way I wanted and so I thought I would share.&lt;/p&gt;
&lt;h6&gt;1. Configure the page rules&lt;/h6&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/425f8a55-ec8e-4103-bff3-5cafc85fadff/CapturePR.png&quot; alt=&quot;Capture-PR&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I decided to point both names at the blog with a temporary redirect as that will allow me to change it in the future.&lt;/p&gt;
&lt;h6&gt;2. Configure the DNS&lt;/h6&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/a41ab7f5-075e-4cc6-9826-8ece24568b70/CaptureDNS.png&quot; alt=&quot;Capture-DNS&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I configured the DNS such that all the domains I wanted to support will route through Cloudflare (the orange cloud image) but instead of being forwarded onto the blog hosting site at ghost.io which would/does fail, the Page Rules above kick-in and do the redirect to blog.many-monkeys.com and all works as I wanted.&lt;/p&gt;
&lt;p&gt;By the way you get three free Page Rules and I only needed to use two, I wonder if I&#39;ll ever find a need for the third.&lt;/p&gt;
</description>
      <pubDate>Sat, 14 Jan 2017 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/configuring-cloudflare-page-rules/</guid>
    </item>
    <item>
      <title>Only time will tell</title>
      <link>https://blog.many-monkeys.com/posts/only-time-will-tell/</link>
      <description>&lt;p&gt;Recently, I decided to review all my old articles that have been scattered across the internet over the past decade or two with the idea of either tidying them up or answering questions that I may have neglected etc.&lt;/p&gt;
&lt;p&gt;During this review I came across an old article from 2007 hosted on &lt;a href=&quot;http://www.codeproject.com/Articles/18834/Create-custom-dialogs-for-use-in-your-Visual-Studi&quot;&gt;CodeProject&lt;/a&gt; that demonstrates a way of creating custom dialogs for Visual Studio setup projects and was not documented by Microsoft. Since I went through the pain of working it all out, I thought I should share what I&#39;d found out in case anyone else was in the same boat and needed to do the same. The problem I now have with this particular article is that people are still asking questions about how to solve something using the technique I provided and all I want to do is shout &amp;quot;No, that was 2007 there is a better way now, there was even a better way then. Don&#39;t any of you read the background of why we did this? Please, just stop!&amp;quot;. I say this because there &lt;em&gt;are&lt;/em&gt; better ways of working with installers and I now feel guilty that I may have sent one too many people down a horrible path, but what do I do? I could delete the article but that would mean that those who have used the article would lose the information I had provided, so instead I decided to add a new section to the top of the article, a sort of a &amp;quot;Caveat Emptor&amp;quot; or &amp;quot;Here be dragons!&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/fa20d746-f9f7-4778-a642-d7311e3b1f09/stop.png&quot; alt=&quot;stop&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I hope it works but only time will tell.&lt;/p&gt;
</description>
      <pubDate>Wed, 13 Jul 2016 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/only-time-will-tell/</guid>
    </item>
    <item>
      <title>Death by a thousand cuts</title>
      <link>https://blog.many-monkeys.com/posts/death-by-a-thousand-cuts/</link>
      <description>&lt;p&gt;Every year I decide to spend some time refreshing OpenCover i.e. upgrading to the latest tools such as Visual Studio, upgrading all the packages that OpenCover depends on etc. etc. and it is never a good time for me.&lt;/p&gt;
&lt;p&gt;I don&#39;t know why I do this to myself, I know it is going to hurt and it&#39;s always the tiny things that somehow take ages to remedy. However I need to do this so that I can uninstall old versions of Visual Studio before I move on to addressing some of the latest features and issues within OpenCover.&lt;/p&gt;
&lt;p&gt;Thing is, as projects go that I have to deal with on a regular basis, OpenCover is one of the simplest, it has around 20 projects and there are around 30 external packages and the majority of those projects and packages are there for testing purposes. I am quite happy about the level of testing (it is not perfect - but when is it ever?) and the number of serious defects are quite low; as of time of writing, the only defects in the &lt;a href=&quot;https://github.com/OpenCover/opencover/issues&quot;&gt;issues&lt;/a&gt; are the ones we raised ourselves from the error logs we received and an issue relating to support for the latest &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/hh549175.aspx&quot;&gt;Fakes&lt;/a&gt; that comes with Visual Studio 2015.&lt;/p&gt;
&lt;p&gt;I&#39;ve decided this time that I am going to list the steps I go through over the next few days (or weeks depending on whatever time I can find) as I do this again for 2016.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Upgrade the project from Visual Studio 2013 to Visual Studio 2015&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;[Note: that I didn&#39;t go for &lt;a href=&quot;https://blogs.msdn.microsoft.com/visualstudio/2016/03/30/visual-studio-15-preview/&quot;&gt;Visual Studio &amp;quot;15&amp;quot;&lt;/a&gt; because it isn&#39;t supported by &lt;a href=&quot;https://github.com/appveyor/ci/issues/753&quot;&gt;AppVeyor yet&lt;/a&gt; and I am not a masochist.]&lt;/li&gt;
&lt;li&gt;Installer project failed to upgrade - upgrade to latest Wix in the 3.X series and try again.&lt;/li&gt;
&lt;li&gt;No errors during upgrade this time.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Building&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Fix C++ issues due to &lt;em&gt;std::hash_map&lt;/em&gt; no longer being &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/0d462wfh.aspx&quot;&gt;supported&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Some C# projects no longer compile due to some Roslyn related intellisense error, what the ...?&lt;/li&gt;
&lt;li&gt;[external package &lt;a href=&quot;https://www.nuget.org/packages/Mono.Gendarme/&quot;&gt;Mono.Gendarme&lt;/a&gt; can no longer be found even though it is in the references, another developer also found this and reported something similar on our &lt;a href=&quot;https://gitter.im/OpenCover/opencover&quot;&gt;gitter channel&lt;/a&gt;.]&lt;/li&gt;
&lt;li&gt;This makes no sense, remove it, add it again - nope, remove it and get ReSharper to add it - nope.&lt;/li&gt;
&lt;li&gt;Check the signing process [the package comes unsigned so I have to manually sign it; is it really that hard to add a strong name key everyone?] - no change, still works in Visual Studio 2013 though. Why me?&lt;/li&gt;
&lt;li&gt;Upgrade to latest ReSharper [thanks again for the freebie JetBrains.], wait....&lt;/li&gt;
&lt;li&gt;Still doesn&#39;t find the reference (yes, I know, it was wishful thinking.) It&#39;s there, I can see it, why don&#39;t you look harder Visual Studio - Roslyn - whatever...!&lt;/li&gt;
&lt;li&gt;... have few beers whilst going round in circles and my &lt;a href=&quot;http://www.urbandictionary.com/define.php?term=google-fu&quot;&gt;google-fu&lt;/a&gt; is failing me.&lt;/li&gt;
&lt;li&gt;New tack, use new ReSharper to decompile library into code and pull the bits I want into a new file, compile, move on - &lt;a href=&quot;https://github.com/mono/mono-tools/blob/077b798b9c7823e42dddd07a4f70cd4dc8ed00af/gendarme/MIT.X11&quot;&gt;bite me&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;Fix installers and other packaging steps due to assembly removal.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Seems changes to the compiler behaviour mean that some of the tests that use the output of the compiler to test how OpenCover works now fail, at least it is consistent in release and debug builds. Fix them up.&lt;/li&gt;
&lt;li&gt;SpecFlow integration tests fail on command line. Have to install new plugin that supports Visual Studio 2015 to run them in Visual Studio using ReSharper.&lt;/li&gt;
&lt;li&gt;Find I can&#39;t debug (use breakpoints that is) tests that have been built as Release even though full PDBs exist. Get latest updates of Visual Studio 2015 i.e. Service pack 2, wait... [I am sure I installed Visual Studio 2015 quicker than it took to service pack it.]. What have they done to the logo..? Never mind, let&#39;s just move on.&lt;/li&gt;
&lt;li&gt;Breakpoints are now working and, okay, fix the parsing [how did we get away with that for so long] and the tests are now passing again.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Building&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Build on the command line again... Success!&lt;/li&gt;
&lt;li&gt;Build &lt;em&gt;release&lt;/em&gt; build on the command line... Success!&lt;/li&gt;
&lt;li&gt;Push to GitHub and run a test build on AppVeyor... Success!&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Upgrading the Packages&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;First undo the hack from what now seems weeks away as I can now once again reference &lt;em&gt;Mono.Gendarme&lt;/em&gt;; It seems the Service Pack fixed many things, I promise I am not bitter about this, much.&lt;/li&gt;
&lt;li&gt;I am now on familiar ground, so let&#39;s have a look at what packages need upgrading using Visual Studio, okay 9 updates, 8 of them are used only for testing and 6 of them have gone through major release number changes; I am worried about these because if there is going to be a breaking change then it&#39;ll be those 6; it&#39;s not showing the solution only packages so I&#39;ll deal with them manually.&lt;/li&gt;
&lt;li&gt;First, upgrade the 3 packages with the potentially least impact i.e. no major version number changes. [By the way, the UI for Nuget package management is far, far better than before]. Build, test... Success!&lt;/li&gt;
&lt;li&gt;Now try the other packages one by one [this allows me to rollback or fix issues with just a single package at a time]. My biggest concern is Nunit and Specflow as these are dependent on each other and my &amp;quot;spider-sense&amp;quot; is tingling, so I am going to leave these to last.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unity&lt;/strong&gt; (used for testing only). Build, test... Success!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;xUnit&lt;/strong&gt; (used for testing only). Build, test... Fail. Update xunit.runners package, find I also need to update nuget.exe itself [at least that is just a one liner], only to find it is empty except for a readme file informing me to download another package. Download that package. Update scripts, build, test, ... Success!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Specflow&lt;/strong&gt; (used for testing only). There are a number of packages all interlinked on versions and dependencies. Now running in a strange universe with two versions of NUnit packages in my solution; I know from past experience they will not play nicely with each in the same folder so will need to take the leap on NUnit soon. Run tests using ReSharper, tests fail due to execution folder no longer the same, fix them up and try again... Success!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NUnit&lt;/strong&gt; (used for testing only). I&#39;ve heard some war stories about this upgrade... Well that went well only one build issue (obsolete method) and easily corrected. Build, test... Fail. It seems more than just obsoleted types have changed, though not sure if it is a NUnit thing or a ReSharper integration thing. Ah, more tests failing due to execution folder has changed, lets solve them first as we have a solution for that. And, now we are left with a change in how we handle fields used for &lt;em&gt;ValueSource&lt;/em&gt;, easy to remedy. Now I need to manually update the runner for the command line build. Build, test... Success! Because I&#39;ve upgraded the test runner I&#39;ll push the build to AppVeyor again just in case something serious has changed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;log4net&lt;/strong&gt; (used in multiple projects). Build, test... Success!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And we&#39;re done, well hopefully, nothing serious has been caught and we are now running on Visual Studio 2015 with the ability to, at last, start using the latest syntax available. Now this upgrade took about 3 days overall with a lot of elapsed time in between whilst I did other things (life) and waiting on stuff to install.&lt;/p&gt;
</description>
      <pubDate>Sun, 22 May 2016 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/death-by-a-thousand-cuts/</guid>
    </item>
    <item>
      <title>Improving your source code quality</title>
      <link>https://blog.many-monkeys.com/posts/improving-your-source-code/</link>
      <description>&lt;p&gt;One reason I work on Open Source projects such as &lt;a href=&quot;https://github.com/OpenCover/opencover&quot;&gt;OpenCover&lt;/a&gt; is so that I can try things out, experiment if you wish, sometimes it&#39;s TDD techniques or a new mocking framework, and sometimes it&#39;s tooling; some of these experiments were successes and some were successful failures; my experiment in using SpecFlow for unit testing was &lt;em&gt;interesting&lt;/em&gt; but I&#39;ll never do that again; my knowledge in what I can do in SpecFlow however has greatly improved.&lt;/p&gt;
&lt;p&gt;Tools help us produce better software, the better our tools &lt;strong&gt;and&lt;/strong&gt; the more we know how to use those tools help us become better developers. Just because you have the best tools and splashed out many $$$ to access those tools, if you don&#39;t learn how to use them properly or at least the basics then you might as well save your money. Thing is, the lack of money in the Open Source world is our problem, we&#39;ve devoted our time and usurped our work laptops to access those &lt;a href=&quot;https://www.visualstudio.com/products/how-to-buy-vs&quot;&gt;expensive IDEs&lt;/a&gt; and additional tooling, but can we really tell our partners we have personally spent thousands on some software or infrastructure to help make better code we are giving away for free. Thankfully we .NET developers now have access to &lt;a href=&quot;https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx&quot;&gt;Visual Studio Community Edition&lt;/a&gt; and we may be able to get away with the odd $100 here and there but &lt;em&gt;Code Quality&lt;/em&gt; tools are probably at the more expensive end of the scale and out of reach for most individuals. There are however a few good &lt;em&gt;Code Quality&lt;/em&gt; tools available to us open source developers for free, in most cases, and they are relatively easy to set up.&lt;/p&gt;
&lt;h5&gt;Coverity&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;https://scan.coverity.com/&quot;&gt;Coverity&lt;/a&gt; was the first quality metric tool we integrated into the OpenCover pipeline; it handles C#, C++ and many others. This tool was suggested sometime ago by one of the OpenCover contributors and we addressed the more serious issues he found at the time but it took a little while before we got round to integrating it into the pipeline. Integration took about a day of tinkering locally and then building the scripts so that it would run on &lt;a href=&quot;https://ci.appveyor.com/project/sawilde/opencover/build/4.6.424&quot;&gt;AppVeyor&lt;/a&gt;; I now ask myself why did we wait? AppVeyor had already preinstalled the Coverity package onto their images and added it to the path so it was quite a simple task. Once we have finally succeeded in uploading our first scan for analysis we got a clean &lt;a href=&quot;https://scan.coverity.com/projects/opencover-opencover&quot;&gt;dashboard&lt;/a&gt; and the ability to configure code exclusions and manage the issues.&lt;/p&gt;
&lt;p&gt;As you can see, a number of issues were found and the team rallied around to fix them. Only a few defects were dismissed as false positives and only under one occasion did fixing one defect introduce another; we are after all only human. We now have it scheduled to run once a week to keep us honest.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/9049466a-a5ca-4740-a8c3-f2d739e3a1f7/coverity.png&quot; alt=&quot;coverity&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can also run Coverity locally on your machine and upload to their site (open source projects only). I&#39;ll provide the steps I used and there are some &lt;a href=&quot;https://www.nuget.org/packages/PublishCoverity/&quot;&gt;nuget packages&lt;/a&gt; about to help you if you wish to use them but I didn&#39;t really feel a need.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installation steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create an account on Coverity and provide some project details for you project. You can&#39;t view the results for free anywhere other than the portal so you might as well do this.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scan.coverity.com/download&quot;&gt;download&lt;/a&gt; the package for your platform, &lt;a href=&quot;http://www.thewindowsclub.com/fix-windows-blocked-access-file&quot;&gt;unblock&lt;/a&gt; and unpack.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Running:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;this is very simple as you just used the supplied tool &lt;code&gt;cov-build.exe&lt;/code&gt; to run your build in our case it is &lt;code&gt;build.bat build-release-platforms-x64&lt;/code&gt; e.g. from the build script&lt;/p&gt;
&lt;exec program=&quot;${coverity.exe}&quot; commandline=&quot;--dir cov-int --encoding=UTF-8 build.bat build-release-platforms-x64&quot;&gt;
&lt;/exec&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Viewing the results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;you will need to upload your results you can use a nuget package for this but I used curl instead e.g. from my build script&lt;/p&gt;
&lt;exec program=&quot;${tools.folder}/7-Zip/7za.exe&quot;&gt;
  &lt;arg value=&quot;a&quot;&gt;
  &lt;arg value=&quot;coverity.zip&quot;&gt;
  &lt;arg value=&quot;cov-int&quot;&gt;
&lt;/arg&gt;&lt;/arg&gt;&lt;/arg&gt;&lt;/exec&gt;
&lt;p&gt;&lt;exec program=&quot;${curl.exe}&quot; commandline=&quot;--form token=${coverity.token} --insecure --form email=${coverity.email} --form file=@coverity.zip --form version=&amp;quot;${ci.buildNumber}&amp;quot; --form description=&amp;quot;${ci.buildNumber}&amp;quot; https://scan.coverity.com/builds?project=OpenCover%2Fopencover&quot;&gt;&lt;/exec&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;wait... sometimes your code gets analysed really quickly and sometimes it doesn&#39;t, there are a few restrictions with open source projects such as frequency of submission and code size.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;play...&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;SonarQube&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;http://www.sonarsource.com/&quot;&gt;SonarSource&lt;/a&gt; has an Open Source offering called &lt;a href=&quot;http://www.sonarqube.org/&quot;&gt;SonarQube&lt;/a&gt; and even offers integration into their own online &lt;a href=&quot;https://nemo.sonarqube.org/&quot;&gt;dashboard&lt;/a&gt;. This integration is not currently available to those who require a windows build platform so until they have implemented their push feature there is probably going to be some sort of hosting outlay to make your results publicly accessible.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/8a029e6f-a336-4766-aed3-49adb0f93fd1/sonar.png&quot; alt=&quot;sonar&quot; /&gt;&lt;/p&gt;
&lt;p&gt;SonarQube is a bit more verbose/pedantic than Coverity and found 13 critical defects. All of these were OWASP related issues due to the &lt;code&gt;Console.WriteLine&lt;/code&gt; statements but since OpenCover is a console application they will all be Resolved as &#39;won&#39;t-fix&#39; or &#39;false-positive&#39;; still trying to work out what is the best approach. In fact it would be easy to dismiss many of the issues found as some of them are a matter of style; SonarQube does allow you to review all the rules and change their usage depending on how the team wishes to treat each rule. In hindsight, before we started fixing the defects found by Coverity, it might have been better to get both products working to compare the output and see if they found the same issues&lt;/p&gt;
&lt;p&gt;One rule that I habitually turn off is the &amp;quot;Literal suffixes should be upper case&amp;quot; rule. This is a &#39;minor&#39; rule that tries to insist that I write my decimals and doubles as &lt;code&gt;0M&lt;/code&gt; and &lt;code&gt;0F&lt;/code&gt; rather than my preferred &lt;code&gt;0m&lt;/code&gt; and &lt;code&gt;0f&lt;/code&gt;; I just think the latter is easier to read. They do at least provide a reason for each rule which in this case is, &#39;Using upper case literal suffixes removes the potential ambiguity between &amp;quot;1&amp;quot; (digit 1) and &amp;quot;l&amp;quot; (letter el) for declaring literals.&#39; i.e. is it &lt;code&gt;0l&lt;/code&gt; or &lt;code&gt;01&lt;/code&gt;, which is fair enough for that case but to then blanket apply the rule is a bit excessive. There are some alternative developer fonts e.g. &lt;a href=&quot;http://hivelogic.com/articles/top-10-programming-fonts&quot;&gt;top-10-programming-fonts&lt;/a&gt;, that you can use in your development environments that make it easier to distinguish the &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;l&lt;/code&gt; if it is such an issue for you and you don&#39;t want to apply the rule like myself.&lt;/p&gt;
&lt;p&gt;I did find setting up SonarQube a lot trickier than Coverity as I also had to self-host, steps were available but just not in one place that I could find. For initial testing I just used the in-memory database but it has some caveats and I have since experimented with a MySql+SonarQube setup on windows and linux. The install steps I used for my initial windows hosted experiment follows&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installation Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;install/update your &lt;a href=&quot;http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html&quot;&gt;Java Runtime Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;download, unblock, and unpack &lt;a href=&quot;https://sonarsource.bintray.com/Distribution/sonarqube&quot;&gt;sonarqube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;download, unblock, and unpack &lt;a href=&quot;https://sonarsource.bintray.com/Distribution/sonar-csharp-plugin&quot;&gt;sonar-csharp-plugin&lt;/a&gt; and place in extensions&lt;/li&gt;
&lt;li&gt;download, unblock, and unpack &lt;a href=&quot;https://github.com/SonarSource/sonar-msbuild-runner/releases&quot;&gt;MSBuild.SonarQube.Runner&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Running:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;*change to match your setup&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run &lt;code&gt;sonarqube-5.3&#92;bin&#92;windows-x86-32&#92;startsonar.bat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;open Visual Studio Developer Prompt 2013/5 and run the following&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&#92;Projects&#92;sonarqube-runner&#92;MSBuild.SonarQube.Runner.exe begin /k:&amp;quot;opencover&amp;quot; /n:&amp;quot;opencover&amp;quot; /v:&amp;quot;0.0.0.1&amp;quot;
msbuild main&#92;OpenCover.sln /t:rebuild
&#92;Projects&#92;sonarqube-runner&#92;MSBuild.SonarQube.Runner.exe end&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Access Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access the site on &lt;a href=&quot;http://localhost:9000/&quot;&gt;http://localhost:9000&lt;/a&gt; using admin/admin&lt;/li&gt;
&lt;li&gt;change password of the setup if publicly accessible.&lt;/li&gt;
&lt;li&gt;play...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are still looking at how we host and integrate SonarQube into our pipeline and we my look into using the c++ community plugin&lt;/p&gt;
&lt;h5&gt;ReSharper&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jetbrains.com/resharper/&quot;&gt;ReSharper&lt;/a&gt; is one of the best productivity tools about for a .NET developer IMO and it also has some built in code quality rules. We&#39;ve been using ReSharper for some time now and often try to get to the ReSharper &amp;quot;Green tick of approval&amp;quot; on the files, in doing so we probably preemptively reduced the number of Coverity and SonarQube issues detected when we ran those tools.&lt;/p&gt;
&lt;h6&gt;Update (25/01/2016)&lt;/h6&gt;
&lt;p&gt;I eventually got round to integrating it into the build pipeline, I used a headless ubuntu vm and followed these &lt;a href=&quot;http://dev.mamikon.net/installing-sonarqube-on-ubuntu/&quot;&gt;instructions&lt;/a&gt;; remembering of course to not use the same &lt;em&gt;default&lt;/em&gt; password. The results of these efforts can be found &lt;a href=&quot;https://http.cat/404&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h6&gt;Update (17/07/2016)&lt;/h6&gt;
&lt;p&gt;I have since migrated the information to &lt;a href=&quot;https://sonarqube.com/overview?id=opencover&quot;&gt;sonarqube.com&lt;/a&gt;; or nemo as it used to be known.&lt;/p&gt;
</description>
      <pubDate>Sat, 23 Jan 2016 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/improving-your-source-code/</guid>
    </item>
    <item>
      <title>A line in the sand</title>
      <link>https://blog.many-monkeys.com/posts/a-line-in-the-sand/</link>
      <description>&lt;p&gt;Just recently I read &lt;a href=&quot;http://amzn.to/1KD6kqx&quot;&gt;Rework&lt;/a&gt; again on my kindle as this book really resonated with me at the time and I thought it was about time I read it again; the book is from the guys at 37 Signals aimed at people starting a business. When I got to the section titled &amp;quot;Draw a line in the sand&amp;quot; I realised that this book is also appropriate to anyone who is thinking of creating/managing or getting involved in an open-source project/product; I am not talking abut flinging up some source code or sending a pull-request and going ta-da, I mean potentially committing several hours per week over many months if not years.&lt;/p&gt;
&lt;p&gt;This particular section in the book talks about drawing a line under what your product does and doesn&#39;t do and asks what are you willing to leave out to keep the product true even if it means some of your customers don&#39;t get the features they want. We see this far too often with great commercial products that start to become bloated as they try to chase every possible sale with more and more features that fewer and fewer people use and with an open source project I think it is all too easy to fall into the trap of fulfilling each feature request because you may think &amp;quot;great, someone wants to use my project but only if I do X, Y and Z by next week.&amp;quot; I&#39;ve had this scenario many times over the years with &lt;a href=&quot;https://github.com/OpenCover/opencover&quot;&gt;OpenCover&lt;/a&gt; and I have to decide whether or not to implement a feature (also do I have the time to do it and how will I support it) so I&#39;ve had to &lt;em&gt;draw a line in the sand&lt;/em&gt; many times using the following criteria &amp;quot;do I need it&amp;quot;. It really is as simple as that, if I don&#39;t need it myself I am not going to spend my time on it. Now that doesn&#39;t mean I will reject code from other developers that meets their needs and enhances the product (especially since they have spent the time and effort to share their work, that would just be churlish) but I have to draw a line under what I am willing to commit to in order that I enjoy working on the project and not feel I am working for someone else, for free.&lt;/p&gt;
&lt;p&gt;One feature I&#39;ve never implemented is creating a UI for OpenCover even though &lt;a href=&quot;https://github.com/sawilde/partcover.net4&quot;&gt;PartCover&lt;/a&gt; (OpenCover&#39;s predecessor) has one, as I felt the UI provided by &lt;a href=&quot;https://github.com/danielpalme/ReportGenerator&quot;&gt;ReportGenerator&lt;/a&gt; was awesome and did the job perfectly that I felt anything I did implement would always be inferior. More recently another UI related feature that I didn&#39;t implement due to lack of personal need was &amp;quot;Visual Studio Integration&amp;quot;, I use &lt;a href=&quot;https://www.jetbrains.com/resharper/&quot;&gt;ReSharper&lt;/a&gt; as a test runner and I don&#39;t actually look at the code coverage until I think I have all the right tests in place; this keeps me honest, I believe, in that it I try to write tests for the code rather than tests for the coverage. However some members of the community wanted one and went and developed an extension themselves, actually there are two extensions currently in development &lt;a href=&quot;https://github.com/OpenCoverUI/OpenCover.UI&quot;&gt;OpenCoverUI&lt;/a&gt; and &lt;a href=&quot;https://github.com/leemorris/Testify&quot;&gt;Testify&lt;/a&gt; which I think is great.&lt;/p&gt;
&lt;p&gt;Another example is a feature that has sat on backlog for over 2 years &amp;quot;&lt;a href=&quot;https://github.com/OpenCover/opencover/issues/144&quot;&gt;Support Coverage of Windows Store Applications on Windows 8&lt;/a&gt;&amp;quot;. I know how to do it, well I have some guidance from &lt;a href=&quot;http://blogs.msdn.com/b/davbr/archive/2013/01/09/writing-a-profiler-of-windows-store-apps.aspx&quot;&gt;David Broman at Microsoft&lt;/a&gt; so I know where to start, but I don&#39;t actually need it. When I write a windows store or phone app I put the majority of the code in an assembly separate from the UI and use unit testing to get the coverage. I don&#39;t care that much about coverage from integration testing as I find the results I get from unit testing far more valuable. Now I know people sometimes in the pursuit of 100% coverage want to get coverage results from integration testing and have some automated UI tests etc and OpenCover will &lt;em&gt;usually&lt;/em&gt; support them. Hooking into windows services was implemented by someone who needed that capability, I tested and accepted their pull-request but I&#39;ve never had to use the capability. IIS integration is tricky, I always use IISExpress myself if I need to go down this path, but the guidance was provided by someone who needed it themselves and so I shared it. One day I may need to implement this particular feature so I am not going to take it down and perhaps if someone wants it beforehand the guidance is on the issue if they want to implement it; though there has been no request for it though either.&lt;/p&gt;
&lt;p&gt;I could list other sections that seemed related and applicable to open source projects e.g. &amp;quot;Be a curator&amp;quot; or &amp;quot;Don&#39;t be a hero&amp;quot;, but frankly I think I would just be listing the entire book contents, best you get &lt;a href=&quot;http://amzn.to/1KD6kqx&quot;&gt;Rework&lt;/a&gt; yourself and read it and then read it again; each time I read it I get something new from it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/7873cd69-bff8-4f07-b659-56bf4e506ee0/rework.jpg&quot; alt=&quot;rework&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image - &lt;a href=&quot;http://www.flickr.com/photos/64588110@N00/6515079935&quot;&gt;Mandala, Coney Beach 4&lt;/a&gt; via &lt;a href=&quot;http://photopin.com/&quot;&gt;photopin&lt;/a&gt; &lt;a href=&quot;https://creativecommons.org/licenses/by-nc-nd/2.0/&quot;&gt;(license)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
      <pubDate>Mon, 03 Aug 2015 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/a-line-in-the-sand/</guid>
    </item>
    <item>
      <title>Free stuff for Open Source .NET development</title>
      <link>https://blog.many-monkeys.com/posts/free-stuff-for-opensource-net-development/</link>
      <description>&lt;p&gt;For the past few years that I&#39;ve been been working on &lt;a href=&quot;https://github.com/OpenCover/opencover&quot;&gt;OpenCover&lt;/a&gt; I&#39;ve had the opportunity to use a number of tools during its development, a few of those are commercial tools that have been made available for free to developers of Open Source projects or just to the project itself because I asked nicely.&lt;/p&gt;
&lt;p&gt;Some of those tools I still use and some just carried the project through part of its journey so I thought it would be nice to give those tools a shout out and perhaps other developers of Open Source projects in this space may find them useful.&lt;/p&gt;
&lt;h4&gt;Development&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx&quot;&gt;Visual Studio - Community Edition&lt;/a&gt;&lt;/strong&gt; - When I first started developing OpenCover I had been previously supporting &lt;a href=&quot;https://github.com/sawilde/partcover.net4&quot;&gt;PartCover&lt;/a&gt; which I had upgraded to support .NET4 so that we could use it for work. Then as I started planning/developing OpenCover I was lucky to have been given a free MSDN licence. Since those days however Microsoft have decided to release a Community Edition of Visual Studio that we developers (subject to some &lt;a href=&quot;https://www.visualstudio.com/support/legal/mt171547&quot;&gt;restrictions&lt;/a&gt;) can use the latest and greatest tooling and really keep ahead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;&lt;/strong&gt; - Unless you&#39;ve been living under a rock for the past few years you probably know what GitHub is; for those rock dwellers it is a source code repository for those using &lt;a href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.jetbrains.com/resharper/&quot;&gt;Resharper&lt;/a&gt;&lt;/strong&gt; - created by JetBrains and probably the mainstay of most .NET developer toolsets at work (after Visual Studio of course). If you have used ReSharper (or any of the JetBrains) tools you&#39;ll know just how more productive you become when you use their tools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.ndepend.com/&quot;&gt;NDepend&lt;/a&gt;&lt;/strong&gt; - was one of the earliest supporters of OpenCover. NDepend also consumes the coverage output from OpenCover (after converting it to the NCover format) and integrates that with its static analysis of your code to produce a wonderful dashboard of your code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/e640befc-49c5-4d1b-8555-298493aa498c/DependencyGraphSnapshot.png&quot; alt=&quot;DependencyGraphSnapshot&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://bitbucket.org/&quot;&gt;BitBucket&lt;/a&gt;&lt;/strong&gt; - similar to GitHub it is a source code repository but supports &lt;a href=&quot;https://en.wikipedia.org/wiki/Mercurial&quot;&gt;Mercurial&lt;/a&gt; as well as Git.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.jetbrains.com/decompiler/&quot;&gt;DotPeek&lt;/a&gt;&lt;/strong&gt; - another great tool from JetBrains and is free. It integrates well with ReSharper but is missing some features such as show IL; when I need to go that low level I use &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/f7dy01k1(v=vs.110).aspx&quot;&gt;ildasm&lt;/a&gt; or more often than not I use &lt;a href=&quot;http://ilspy.net/&quot;&gt;ILSpy&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Continuous Integration&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.atlassian.com/software/bamboo&quot;&gt;Bamboo&lt;/a&gt;&lt;/strong&gt; - another tool provided by Atlassian, this was the first build system used to build OpenCover based on commits pushed up to GitHub. It wasn&#39;t totally free as I still had to pay the compute usage of the windows image I was running in AWS but it rarely went over $5 a month so I can&#39;t really complain. It was quite configurable and as I already had a command line build script it was easy to set up and integrate. It was lacking a few features at the time such as building on pull requests etc but it was useful as it meant that I could check that anything I pushed would build on another developer&#39;s machine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.appveyor.com/&quot;&gt;AppVeyor&lt;/a&gt;&lt;/strong&gt; - is awesome, I can&#39;t rave enough about how great this CI system is for .NET developers. It&#39;s so easy to set up that I use it on some other .NET projects that I am involved with e.g. &lt;a href=&quot;https://github.com/OpenCoverUI/OpenCover.UI&quot;&gt;OpenCover.UI&lt;/a&gt; and &lt;a href=&quot;https://github.com/MYOB-Technology/AccountRight_Live_API_.Net_SDK&quot;&gt;AccountRight Live API SDK&lt;/a&gt;. It works with pull requests and the nicest thing is that it also integrates with Nuget/MyGet and GitHub so I automate the pushing of releases by just pushing the code to a specific branch.&lt;/p&gt;
&lt;h4&gt;Reporting&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/danielpalme/ReportGenerator&quot;&gt;ReportGenerator&lt;/a&gt;&lt;/strong&gt; - is a great tool for visualizing the output from OpenCover.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://coveralls.io/&quot;&gt;Coveralls.io&lt;/a&gt;&lt;/strong&gt; - I use Coveralls to display online the test coverage of my projects, yes I actually use OpenCover to get coverage statistics of OpenCover. The online nature means that any contributors of pull-requests can get that coverage feedback.&lt;/p&gt;
</description>
      <pubDate>Sat, 25 Jul 2015 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/free-stuff-for-opensource-net-development/</guid>
    </item>
    <item>
      <title>Moving blogging platform to Ghost</title>
      <link>https://blog.many-monkeys.com/posts/moving-blogging-platform-to-ghost/</link>
      <description>&lt;p&gt;Welcome to my new blog. Like it? I hope you do as I know I prefer it to the the Blogger version I was originally using. Moving platforms had its ups and downs so I thought I would detail a bit of the journey.&lt;/p&gt;
&lt;p&gt;Getting started was quite easy, I decided to trial it with &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost&lt;/a&gt; where the nice guys there will do the import for you (of course they will, they want you to sign up with them). Most of the transformation went without a hitch but I have quite a few code samples and not all of them converted properly and so I had to do that work myself. Thankfully &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost&lt;/a&gt; uses &lt;a href=&quot;https://guides.github.com/features/mastering-markdown/&quot;&gt;Markdown&lt;/a&gt; so with a bit of abuse of the &lt;/p&gt;&lt;pre&gt; tag I managed to get some semblance of order to the posts. But it wasn&#39;t perfect as the code samples were rather plain and I rather liked the code-highlighter script I was using on Blogger. To get round this I needed to work out how to create my own theme.&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Creating your own theme sounds daunting doesn&#39;t it, I know I was already in strange waters so I was initially hesitant to go down this path. I looked at using the &lt;strong&gt;Code Injection&lt;/strong&gt; section but unless the highlighter code I was intending to use had a CDN or I had an alternate hosting location this was going to get messy and very quickly unwieldy. I also wanted to use my little purple monkey icon for the &lt;em&gt;favicon.ico&lt;/em&gt; and I couldn&#39;t see how I could do that within the management portal. So, I had a deeper investigation into how themes are deployed into Ghost via the portal and quickly realised it was just a zip&#39;d up folder of files. I actually liked the default &lt;a href=&quot;https://github.com/TryGhost/Casper&quot;&gt;Casper&lt;/a&gt; theme so I used Github to fork the repo and then branched again to make my changes. I know it seems complex but I wanted a way to apply any fixes back (should, in the unlikely event, I find any) but more so I could take fixes from the original and apply them to my branch and even cherry pick changes should I so wish. Eventually I suspect the changes I will probably make will make this a near impossible task but until then...&lt;/p&gt;
&lt;p&gt;So applying the &lt;em&gt;favicon.ico&lt;/em&gt; change seemed the simplest thing to start with and with a little help from &lt;a href=&quot;https://www.ghostforbeginners.com/how-to-add-a-favicon-to-your-ghost-blog/&quot;&gt;Ghost For Beginners&lt;/a&gt; (an excellent resource) I was on my way; you can see my change here on &lt;a href=&quot;https://github.com/sawilde/Casper/commit/e5f154ccad5aa7f170c17d3dba958edcf7bec69b&quot;&gt;github&lt;/a&gt;. Emboldened I decided to try my next change which was add a code highlighter script. It was suggested I try &lt;a href=&quot;http://prismjs.com/download.html&quot;&gt;Prism&lt;/a&gt; and as it had most of the features I wanted I gave it go; see change here on &lt;a href=&quot;https://github.com/sawilde/Casper/commit/3318169692fb146cf26947eb6fb6f5f95c351cee&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Both these changes were quite simple and testing them by zipping the folder and uploading via the portal was quite easy. It would be nice to be able to push my changes via Git (as all the cool kids like to do) but for now it would suffice.&lt;/p&gt;
&lt;p&gt;Now all I had to do was re-edit my posts and apply the appropriate markup and I was done.&lt;/p&gt;
&lt;/pre&gt;</description>
      <pubDate>Sat, 18 Jul 2015 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/moving-blogging-platform-to-ghost/</guid>
    </item>
    <item>
      <title>Using GMock with Visual Studio CppUnitTestFramework</title>
      <link>https://blog.many-monkeys.com/posts/using_gmock_with_visual_studio_cpp_unit_test_framework/</link>
      <description>&lt;p&gt;One of the things I have been a bit disappointed with myself during the development of &lt;a href=&quot;https://github.com/OpenCover/opencover&quot;&gt;OpenCover&lt;/a&gt; is the lack of unit testing around the C++ code that makes up the profiler.&lt;/p&gt;
&lt;p&gt;I did toy with &lt;a href=&quot;https://code.google.com/p/googletest/&quot;&gt;GTest&lt;/a&gt; and got some decent tests around the instrumentation engine but I was never able to actually test the profiler callbacks, also I found the lack of GTest integration with Visual Studio quite irritating; I know I have been spoilt by ReSharper. Recently however, during handling &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/hh549175.aspx&quot;&gt;Fakes&lt;/a&gt; through OpenCover, I had an opportunity to work out how to load the profiler using registry free loading and realised that perhaps such testing might be within my reach, what I was missing however was a mocking library and one that I could use with Visual Studio tooling.&lt;/p&gt;
&lt;p&gt;Frankly GMock was the only candidate, the commercial alternatives being out as this was for an OSS project, but the instructions all seemed to want to build a number of libraries (64/32 bit Debug/Release) that I would have to statically link to and maintain these builds should the source or build options change. I decided to try a different tack that wouldn&#39;t involve building libraries and it has worked out reasonably successful, so I thought it would be worth commenting on here.&lt;/p&gt;
&lt;h4&gt;Step 1&lt;/h4&gt;
&lt;p&gt;Get the latest GMock (1.7.0) library as a zip file and uncompress it somewhere within your repository.&lt;/p&gt;
&lt;h4&gt;Step 2&lt;/h4&gt;
&lt;p&gt;From within Visual Studio update the Additional Include Directories to include the following paths&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;SolutionDir&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;lib&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;gmock-1.7.0
&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;SolutionDir&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;lib&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;gmock-1.7.0&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;include
&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;SolutionDir&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;lib&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;gmock-1.7.0&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;gtest
&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;SolutionDir&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;lib&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;gmock-1.7.0&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;gtest&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;include
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 3&lt;/h4&gt;
&lt;p&gt;Add the following to your &amp;quot;stdafx.h&amp;quot;&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;gmock/gmock.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;gtest/gtest.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 4&lt;/h4&gt;
&lt;p&gt;Add the following to your &amp;quot;stdafx.cpp&amp;quot;&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// The following lines pull in the real gmock *.cc files.&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gmock-cardinalities.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gmock-internal-utils.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gmock-matchers.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gmock-spec-builders.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gmock.cc&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The following lines pull in the real gtest *.cc files.&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gtest.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gtest-death-test.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gtest-filepath.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gtest-port.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gtest-printers.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gtest-test-part.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/gtest-typed-test.cc&quot;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 5&lt;/h4&gt;
&lt;p&gt;Now all you need to do is add initialise GMock and you are ready; as I am using the CppUnitTestFramework I do the following.&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;TEST_MODULE_INITIALIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ModuleInitialize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// enable google mock&lt;/span&gt;
&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;testing&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GTEST_FLAG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;throw_on_failure&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
TCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;argv &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;testing&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;InitGoogleMock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now all you need to do is follow the GMock documentation and add some expectations etc you can as I discovered even mock COM objects and have expectations on them e.g.&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;EXPECT_CALL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;profilerInfo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SetEventMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EVENT_MASK_WHEN_FAKES&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Times&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WillRepeatedly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;S_OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Bonus Round&lt;/h4&gt;
&lt;p&gt;There were a few little niggles however the first of which is that if an expectation fails, the Visual Studio test runner takes a little too long to close down (I suspect this may be something on my machine related to DrWatson). The second was that if an expectation did fail I could only initially see the result using DebugView - ugh - however I found a solution at &lt;a href=&quot;http://www.durwella.com/post/96457792632/extending-microsoft-cppunittestframework&quot;&gt;http://www.durwella.com/post/96457792632/extending-microsoft-cppunittestframework&lt;/a&gt; which involves using some extra macros; I added these to my &amp;quot;stdafx.h&amp;quot; and voila the results are now available in Visual Studio. Finally, I found the mocks were not very lightweight and in fact if I left them hooked in caused performance issues, replacing them with an admittedly less useful stubs I could avoid this when necessary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 20/2/2016&lt;/strong&gt; The link to www.durwella.com has stopped working, but a copy of the article can be found on tumblr - &lt;a href=&quot;http://durwella.tumblr.com/post/96457792632/extending-microsoft-cppunittestframework#96457792632&quot;&gt;http://durwella.tumblr.com/post/96457792632/extending-microsoft-cppunittestframework#96457792632&lt;/a&gt;. For completeness however I am posting the macros here as well with all attribution belonging to durwella.com&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;_TEST_METHOD_EX_EXPANDER&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_testMethod&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
	&lt;span class=&quot;token expression&quot;&gt;_testMethod &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Adds support for seeing std::exception in test output. Requires TEST_METHOD_EX_END after test.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Example:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// TEST_METHOD_EX_BEGIN(MyFailingTest){ throw std::exception(&quot;What happened&quot;); } TEST_METHOD_EX_END;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;TEST_METHOD_EX_BEGIN&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_methodName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_TEST_METHOD_EX_EXPANDER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;TEST_METHOD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_methodName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Use following test declared with TEST_METHOD_EX_BEGIN&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;TEST_METHOD_EX_END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
	&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;exception&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
	&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;wstringstream ws&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ws &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Unhandled Exception:&quot;&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Microsoft&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;VisualStudio&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CppUnitTestFramework&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Fail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ws&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
	&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
</description>
      <pubDate>Fri, 03 Apr 2015 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/using_gmock_with_visual_studio_cpp_unit_test_framework/</guid>
    </item>
    <item>
      <title>Happy Birthday OpenCover</title>
      <link>https://blog.many-monkeys.com/posts/happy_birthday_open_cover/</link>
      <description>&lt;h4&gt;Happy Birthday&lt;/h4&gt;
&lt;p&gt;Today &lt;a href=&quot;https://github.com/OpenCover/opencover&quot;&gt;OpenCover&lt;/a&gt; is 4 (four) years old, where has the time gone? In that time it has had over 60,000 &lt;a href=&quot;http://www.nuget.org/packages/opencover&quot;&gt;nuget downloads&lt;/a&gt;, been adopted by the SharpDevelop community as the coverage tool for their IDE, and, as I found out the other day, is also being used by the &lt;a href=&quot;https://github.com/dotnet/corefx&quot;&gt;corefx team&lt;/a&gt; to supply &lt;a href=&quot;http://dotnet-ci.cloudapp.net/job/dotnet_corefx_coverage_windows/Code_Coverage_Report/&quot;&gt;coverage information&lt;/a&gt; on their tests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/a10f4ad6-162c-4404-a31e-3d2a21d4ff73/yes.jpg&quot; alt=&quot;yes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Four years ago I started on OpenCover (&lt;a href=&quot;https://github.com/OpenCover/opencover/commit/23ecce5026b5f609faad57bae3917d4248749316&quot;&gt;first commit&lt;/a&gt; - not very interesting but a stake in the ground) in order to create a code coverage tool for the .NET platform that could be used by anyone, but especially so that those of us in the open source community could have a tool available to us to help enhance our testing feedback; in the past we have seen some tools go commercial, some just vanish and others just abandoned. I also wanted to share some of the knowledge I had picked up in this area but no longer used in my day-to-day activities and to ensure it remains within the community by making it maintainable and available without restriction.&lt;/p&gt;
&lt;p&gt;It took nearly 6 months to get the first &lt;a href=&quot;https://monkey-see-monkey-do-blog.herokuapp.com/2011/06/opencover-first-beta-release&quot;&gt;beta release&lt;/a&gt; and since that time we have added sequence and branch coverage, support for .NET 2 and .NET 4+, 32 and 64 bit support, and even Silverlight. Later features such as coverage by test and hooking into services and IIS support; not everything works as seamlessly as I would like but the community has either lived with it or improved it - which was the outcome I was seeking. Just recently we even added support for Microsoft.Fakes because some people wanted to use OpenCover for coverage with their tests that used Fakes rather than the coverage tool that they already had available; that was an interesting learning exercise, as well due to  some very fortuitous googling.&lt;/p&gt;
&lt;p&gt;There even seems to be some movement to make a Mono version of OpenCover which was not something I saw coming but is also quite exciting, especially as Visual Studio now has support for Android and iPhone development, we knew about Xamarin/Mono but actual Visual Studio integration? Who 4 years ago would have seen that one coming ...?&lt;/p&gt;
&lt;h4&gt;Highlights&lt;/h4&gt;
&lt;p&gt;One of the highlights of the past few years was starting at my current place of work (MYOB) and then overhearing a conversation within the devops/build team who were discussing the coverage results of this free coverage tool they had found on github, imagine my delight when I realised it was OpenCover they were discussing, and, in mostly favourable terms; this was the first place I had seen OpenCover being used and it wasn&#39;t even introduced by me. I secretly implemented a &lt;a href=&quot;https://github.com/OpenCover/opencover/issues/133&quot;&gt;feature&lt;/a&gt; in response to their comments.&lt;/p&gt;
&lt;p&gt;Another highlight is seeing that at least two Visual Studio integrations involving OpenCover are currently in play, both of these have been started independently, and though I am currently partly involved with one of them it will be interesting to see how they both progress.&lt;/p&gt;
&lt;p&gt;I&#39;d like to thank everyone who has contributed to OpenCover either through direct contribution, suggestions, free stuff (more please) and just using it. Here&#39;s to another 4+ interesting years and I wonder what will happen to OpenCover in that time - suggestions?&lt;/p&gt;
</description>
      <pubDate>Sun, 22 Feb 2015 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/happy_birthday_open_cover/</guid>
    </item>
    <item>
      <title>Microservices... Where to Start?</title>
      <link>https://blog.many-monkeys.com/posts/microservices_where_to_start_/</link>
      <description>&lt;p&gt;Micro-services are becoming a &amp;quot;thing&amp;quot; now and are probably de-facto when someone begins a new project and are thinking about hosting in the cloud but where do you start when you have a brown field project. Now I don&#39;t have any hot answers or amazing insights here all I can do is describe what my first &amp;quot;micro-service&amp;quot; was and how it came into being.&lt;/p&gt;
&lt;p&gt;Over time the application was getting more use and the number of servers involved started to increase; we were using auto-scaling and the number of servers increased in line with usage but wavered between 8 and 24 instances. This quite rightly caused some consternation so we tinkered with number of core settings for each instance and thresholds for triggers to scale up and down but nothing seemed to alter the number of total cores being used. We actually have a hefty bit of logging and we can control the output through logging levels so we decided to change the logging to try and get more diagnostic information and this is when things got interesting. As this is a production system getting hold of this log information was initially problematic and slow so we had already started forwarding all the messages to &lt;a href=&quot;https://www.splunkstorm.com/&quot;&gt;SplunkStorm&lt;/a&gt; using the available API and all was well (for over a year) and we were very impressed with how we could use that information for ad-hoc queries. However when we changed the logging levels the servers started scaling and we started to get database errors; unusual ones involving SQL connection issues rather than SQL query errors. We quickly reverted the changes and decided to try and replicate the problem in our CI/SIT environments.&lt;/p&gt;
&lt;p&gt;What we realized was that it was our own logging that was causing our performance issues and even more awkwardly was also responsible for the SQL connection issues as the logging to SplunkStorm via its API was using up the available TCPIP connections; this was even more pronounced when we changed the logging level. What we needed to do was refactor our logging such that we could get all our data into SplunkStorm (and Splunk as we were also in the process of migrating to SplunkStorm&#39;s big brother) with minimum impact to the actual production systems. Thankfully our logging framework used NLog, which we had wrapped in another entity for mocking purposes, so what we decided to do was write a new NLog target that would instead log to a queue (service-bus) and then have another service read messages from that queue and forward them to Splunk and SplunkStorm and thus our first micro-service was born.&lt;/p&gt;
&lt;p&gt;The new NLog target took the log messages, batch pushed them to the queue, then a microservice was written that monitors the queue, pulls messages off in batches, and then pushes them to Splunk and SplunkStorm, also in batches. The initial feasibility spike took 1/2 a day with the the final implementation being ready and pushed into production the following week. Because we were using .NET we could also take advantage of multiple threads so we used thead-pools to limit the number of active Splunk/SplunkStorm messages being sent in parallel. What we found after deployment was that we could scale back our main application servers to 4 instances with only a pair of single core services dealing with the logging aspect, we also noticed that the auto scaling never reaches its old thresholds and the instance count has been stable ever since. Another advantage is that the queue can now be used by other services to push messages to Splunk and can even use the same NLog target in their projects to deal with all the complexities.&lt;/p&gt;
&lt;p&gt;I hope the above shows that your first micro-service does not have to be something elaborate but instead deal with a mundane but quite essential task and the benefits can be quite astounding.&lt;/p&gt;
</description>
      <pubDate>Wed, 29 Oct 2014 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/microservices_where_to_start_/</guid>
    </item>
    <item>
      <title>Excluding code from coverage...</title>
      <link>https://blog.many-monkeys.com/posts/excluding_code_from_coverage_/</link>
      <description>&lt;p&gt;This may (no guarantees) turn into a series of posts on how to refactor your code for testing using simple examples.&lt;/p&gt;
&lt;p&gt;This particular example came from a request to add an &amp;quot;Exclude Lines from Coverage&amp;quot; feature to &lt;a href=&quot;https://github.com/OpenCover/opencover&quot;&gt;OpenCover&lt;/a&gt;. Now there are many ways this could be achieved, none of which I had any appetite for as they were either too clunky and/or could make OpenCover very slow. I am also not a big fan on excluding anything from code coverage; though OpenCover has several exclude options I just thought that this was one step too far in order to achieve that 100% coverage value as it could too easily abused. Even if I did think the feature was useful it still may not get implemented by myself for several days, weeks or months.&lt;/p&gt;
&lt;p&gt;But sometimes there are other ways to cover your code without a big refactoring and mocking exercise which can act as a deterrent to doing the right thing.&lt;/p&gt;
&lt;p&gt;In this case the user was using EntityFramework and wanted to exclude the code in the catch handlers because they couldn&#39;t force EntityFramework to crash on demand - this is quite a common problem in my experience. The user also knew that one approach was to push all that EntityFramework stuff out to another class and could then test their exception handling via mocks but didn&#39;t have the time/appetite to go down that path and thus wanted to exclude that code.&lt;/p&gt;
&lt;p&gt;I imagined that the user has code that looked something like this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SaveCustomers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ILogger&lt;/span&gt; logger&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;CustomersEntities&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; CustomersEntities&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// awsome stuff with EntityFramework&lt;/span&gt;
    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SaveChanges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do some awesome logging&lt;/span&gt;
    logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I could see why this would be hard (but not impossible) to test the exception handling. Now instead of extracting out all the interactions with the EntityFramework so it is possible to throw an exception during testing I suggested the following refactoring:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CallWrapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Action&lt;/span&gt; doSomething&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ILogger&lt;/span&gt; logger&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do some awesome logging&lt;/span&gt;
    logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which I would then use like this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SaveCustomers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ILogger&lt;/span&gt; logger&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;CustomersEntities&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; CustomersEntities&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;CallWrapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// awsome stuff with EntityFramework&lt;/span&gt;
    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SaveChanges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My original tests should still continue as before and now I have a new method that I can now test independently.&lt;/p&gt;
&lt;p&gt;I know this isn&#39;t the only way to tackle this sort of problem and I&#39;d love to hear about other approaches.&lt;/p&gt;
</description>
      <pubDate>Mon, 13 Oct 2014 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/excluding_code_from_coverage_/</guid>
    </item>
    <item>
      <title>A simple TDD example</title>
      <link>https://blog.many-monkeys.com/posts/a_simple_tdd_example/</link>
      <description>&lt;p&gt;I recently posted a response to &lt;a href=&quot;http://stackoverflow.com/a/26152423/189163&quot;&gt;StackOverflow wrt TDD and Coverage&lt;/a&gt; and I thought it would be worth re-posting the response here. The example is simple but hopefully shows how writing the right tests using TDD gives you a better suite of tests for your code than you would probably write if you wrote the tests after the code (which may have been re-factored as you developed).&lt;/p&gt;
&lt;p&gt;&amp;quot;As the [original] accepted answer has pointed out your actual scenario reduces to collection.Sum() however you will not be able to get away with this every time.&lt;/p&gt;
&lt;p&gt;If we use TDD to develop this (overkill I agree but easy to explain) we would [possibly] do the following (I am also using &lt;a href=&quot;http://www.nunit.org/&quot;&gt;NUnit&lt;/a&gt; in this example out of preference).&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Sum_Is_Zero_When_No_Entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; bomManager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;BomManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bomManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;MethodToTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; Collection&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then write the following code (note: we write the minimum to meet the current set of tests)&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MethodToTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Collection&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; sum&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We would then write a new test e.g.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;token attribute-arguments&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Sum_Is_Calculated_Correctly_When_Entries_Supplied&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; expected&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; bomManager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;BomManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bomManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;MethodToTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; Collection&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we ran our tests they would all pass (green) so we need a new test(cases)&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;token attribute-arguments&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;token attribute-arguments&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to satisfy those tests I would need to modify my code e.g.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MethodToTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Collection&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    sum &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; sum&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now all my tests work and if I run that through &lt;a href=&quot;http://www.nuget.org/packages/opencover&quot;&gt;OpenCover&lt;/a&gt; I get 100% sequence and branch coverage - Hurrah!.... And I did so without using coverage as my control but writing the right tests to support my code.&lt;/p&gt;
&lt;p&gt;BUT there is a &#39;possible&#39; defect... what if I pass in null? Time for a new test to investigate&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Sum_Is_Zero_When_Null_Collection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; bomManager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;BomManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bomManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;MethodToTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The test fails so we need to update our code e.g.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MethodToTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Collection&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collection &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        sum &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; sum&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we have tests that support our code rather than tests that test our code i.e. our tests do not care about how we went about writing our code.&lt;/p&gt;
&lt;p&gt;Now we have a good set of tests so we can now safely refactor our code e.g.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MethodToTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IEnumerable&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collection &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And I did so without affecting any of the existing tests.&amp;quot;&lt;/p&gt;
</description>
      <pubDate>Mon, 06 Oct 2014 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/a_simple_tdd_example/</guid>
    </item>
    <item>
      <title>The API Journey for AccountRight Live</title>
      <link>https://blog.many-monkeys.com/posts/the-api-journey-for-accountright-live/</link>
      <description>&lt;p&gt;My talk at ALT.NET on designing the MYOB API.&lt;/p&gt;
&lt;p&gt;&amp;quot;Building an API for your product isn’t just about choosing your technology and planning your scaling capabilities when you unleash it upon the world. For nearly 2 years MYOB have been developing an API for our AccountRight Live product and we would like to share with you our journey into making an API that is used by our own products, such as PayDirect, and one that our developer partners can also use productively - “Integrating with the MYOBapi has been so quick for us. For example [when] MYOBapi let us know when the new endpoints were available for payroll we were able to complete our full depth integration over the space of 16 hours.&amp;quot;&lt;/p&gt;
&lt;p&gt;The full talk can be found &lt;a href=&quot;https://www.youtube.com/watch?v=nxEcjFG0tl4-Y&quot;&gt;here&lt;/a&gt; on YouTube.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=nxEcjFG0tl4-Y&quot; title=&quot;Play Now&quot;&gt;&lt;img src=&quot;https://ucarecdn.com/5460afa8-8bd9-4602-924d-62309271c13d/YTCapture.jpg&quot; alt=&quot;Play Now&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Tue, 29 Jul 2014 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/the-api-journey-for-accountright-live/</guid>
    </item>
    <item>
      <title>Customsing New Relic installation during Azure deployments</title>
      <link>https://blog.many-monkeys.com/posts/customsing_new_relic_installation_during_azure_deployments/</link>
      <description>&lt;p&gt;For about a year we&#39;ve been running New Relic to monitor our WebRoles running on the Azure platform. Installing has been quite simple by following the instructions initially found on the &lt;a href=&quot;https://docs.newrelic.com/docs/dotnet/&quot;&gt;New Relic&lt;/a&gt; site and is now available via &lt;a href=&quot;http://www.nuget.org/packages/NewRelicWindowsAzure&quot;&gt;Nuget&lt;/a&gt;; however two things about this process have been irking me.&lt;/p&gt;
&lt;p&gt;First, I wanted to be able to distinguish the CI and Production deployments in the New Relic portal by making them have different names, but the name as it appears in the New relic portal is controlled through a setting in the web.config and cannot be controlled though the Azure portal.&lt;/p&gt;
&lt;p&gt;Second, I wanted to be able to control the licence key we used for CI (free licence, limited functionality) and Production (expensive licence, full functionality) deployments, however the key is embedded in the newrelic.cmd and is applied when the New Relic agent is installed; this is not easy to change during/post deployment.&lt;/p&gt;
&lt;p&gt;The initial solution to both these problems involved producing two packages, one for the CI environment(s) and one for the Production environment. Instead of the normal Debug and Release build outputs, a 3rd target, Production, was used and the web.config was modified during the build process using a &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd465318(v=vs.100).aspx&quot;&gt;transform&lt;/a&gt; that changed the name to what was wanted. The licence key issue was resolved by have two newrelic.cmd items in the project and then packaging the required one with the appropriate build. This was not ideal but it worked in a fashion however the ProdOps guys were keen on having control over the name and licence key used in production.&lt;/p&gt;
&lt;h4&gt;Changing the Application name&lt;/h4&gt;
&lt;p&gt;New Relic gets the Application name from a setting in the web.config and so what is necessary is to read a setting in the Azure configuration and update the web.config. There are many ways to resolve this issue but the approach we took was based on the solution to an identical issue raised on GitHub.  
For completeness I will however reiterate the steps below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the ServiceDefinition.csdef file add a setting to the &lt;ConfigurationSettings&gt; section&lt;/ConfigurationSettings&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code class=&quot;language-markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ConfigurationSettings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Setting&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;NewRelicApplicationName&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ConfigurationSettings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;In the ServiceConfiguration file for your environment add a setting that will be used to set the Application name in New Relic&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code class=&quot;language-markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ConfigurationSettings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Setting&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;NewRelicApplicationName&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;MyApplication&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ConfigurationSettings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;In the WebRole.cs file for your application amend your code with the following&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WebRole&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token type-list&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;RoleEntryPoint&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OnStart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;ConfigureNewRelic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;OnStart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ConfigureNewRelic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;RoleEnvironment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IsAvailable &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;RoleEnvironment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IsEmulated&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; appName&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                appName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RoleEnvironment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetConfigurationSettingValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;NewRelicApplicationName&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;RoleEnvironmentException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;/*nothing we can do so just return*/&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; server &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;ServerManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;// get the site&#39;s web configuration&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; siteNameFromServiceModel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Web&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; siteName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{0}_{1}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; RoleEnvironment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CurrentRoleInstance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; siteNameFromServiceModel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; siteConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Sites&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;siteName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetWebConfiguration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token comment&quot;&gt;// get the appSettings section&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; appSettings &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; siteConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;appSettings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCollection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;AddConfigElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appSettings&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NewRelic.AppName&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; appName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CommitChanges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AddConfigElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConfigurationElementCollection&lt;/span&gt; appSettings&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appSettings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetAttributeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            appSettings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;appSettings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;First&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetAttributeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token class-name&quot;&gt;ConfigurationElement&lt;/span&gt; addElement &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; appSettings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CreateElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        addElement&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        addElement&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        appSettings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;addElement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that should be it.&lt;/p&gt;
&lt;h4&gt;Changing the New Relic licence key&lt;/h4&gt;
&lt;p&gt;The New Relic licence key is applied when the New Relic agent is installed on the host so what we is needed is to read the Azure configuration when the newrelic.bat is executed as part of the Startup tasks (defined in the ServiceDefinition.csdef) and apply it when the agent is installed. There does not appear to be way of changing the licence key if your agents have already been installed other than reducing the number of instances to 0 and then scaling back up (I suggest you use the staging slot for this). In the ServiceDefinition.csdef file add a setting to the &lt;ConfigurationSettings&gt; section&lt;/ConfigurationSettings&gt;&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code class=&quot;language-markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ConfigurationSettings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Setting&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;NewRelicLicenceKey&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;Setting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ConfigurationSettings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and add a new Environment variable to the newrelic.cmd startup task that will be set by the new configuration setting&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code class=&quot;language-markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;task&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;commandline&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;newrelic.cmd&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;executioncontext&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;elevated&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;tasktype&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;simple&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;variable&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;EMULATED&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;roleinstancevalue&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xpath&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/RoleEnvironment/Deployment/@emulated&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;roleinstancevalue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;variable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;variable&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;NewRelicLicence&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- http://msdn.microsoft.com/en-us/library/windowsazure/hh404006.aspx --&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;roleinstancevalue&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xpath&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[@name=&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;apos;&quot;&gt;&amp;amp;apos;&lt;/span&gt;NewRelicLicenceKey&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;apos;&quot;&gt;&amp;amp;apos;&lt;/span&gt;]/@value&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;roleinstancevalue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;variable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;variable&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;IsWorkerRole&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;false&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;variable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the ServiceConfiguration file for your environment add a setting that will be used to set the Application name in New Relic&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code class=&quot;language-markup&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;configurationsettings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;setting&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;NewRelicLicenceKey&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&amp;lt;ADD YOUR KEY HERE&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;setting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;configurationsettings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Edit your newrelic.cmd to use the Environment variable&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;:: Update with your license key
SET &lt;span class=&quot;token assign-left variable&quot;&gt;LICENSE_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;%NewRelicLicenceKey%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you should be able to control the New Relic licence key during your deployment.&lt;/p&gt;
</description>
      <pubDate>Thu, 03 Apr 2014 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/customsing_new_relic_installation_during_azure_deployments/</guid>
    </item>
    <item>
      <title>Book Review - Building Mobile Applications Using Kendo UI Mobile and ASP.NET Web API</title>
      <link>https://blog.many-monkeys.com/posts/book_review_building_mobile_applications_using_kendo_ui_mobile_and_asp_net_web_api/</link>
      <description>&lt;p&gt;I&#39;ve written a book review on &#39;Building Mobile Applications Using Kendo UI Mobile and ASP.NET Web API&#39; and posted it up on &lt;a href=&quot;http://www.codeproject.com/Articles/696464/Building-Mobile-Applications-Using-Kendo-UI-Mobile&quot;&gt;CodeProject&lt;/a&gt;. &lt;strong&gt;Summary&lt;/strong&gt; I liked this book and I took a lot from it that I am now using to build that sample application using &lt;a href=&quot;http://www.kendoui.com/&quot;&gt;KendoUI&lt;/a&gt;. If you want to learn about ASP.NET Web API then this book isn&#39;t for you and you&#39;ll learn a lot more from the &lt;a href=&quot;http://www.asp.net/web-api&quot;&gt;ASP.NET Web API&lt;/a&gt; site.&lt;/p&gt;
</description>
      <pubDate>Sat, 14 Dec 2013 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/book_review_building_mobile_applications_using_kendo_ui_mobile_and_asp_net_web_api/</guid>
    </item>
    <item>
      <title>Getting code coverage from your .NET testing using OpenCover.</title>
      <link>https://blog.many-monkeys.com/posts/getting-code-coverage-from-your-net-testing-using-opencover/</link>
      <description>&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;OpenCover is a free, &lt;a href=&quot;https://github.com/sawilde/opencover&quot;&gt;open-sourced&lt;/a&gt;, code coverage tool for .NET 2.0 and above running on the .NET platform. It supports sequence coverage, branch coverage and has a cover by test facility. Though OpenCover is command line only, a rich HTML UI of the results can be visualized using &lt;a href=&quot;http://reportgenerator.codeplex.com/&quot;&gt;ReportGenerator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We will aim to demonstrate how you can use this utility to get visibility into your testing coverage.&lt;/p&gt;
&lt;h3&gt;Background&lt;/h3&gt;
&lt;p&gt;OpenCover is currently the only actively developed and maintained open-sourced tool of it&#39;s type for the .NET platform but it was not the first, some of the others being:&lt;/p&gt;
&lt;p&gt;NCover - Probably the most well-known commercial tool for .NET code coverage started life as an &lt;a href=&quot;http://sourceforge.net/projects/ncover/?source=directory&quot;&gt;open-source&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;Coverage.eye - Originated at Microsoft and was available on gotdotnet, the repository/sample has since gone and no full mirrors appear to exist (The wayback machine only has the &lt;a href=&quot;http://web.archive.org/web/20080122001923/http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=881a36c6-6f45-4485-a94e-060130687151&quot;&gt;text&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;PartCover - This appears to have been created in response to NCover going commercial and though actively used it has limitations e.g. 32-bit only. The original &lt;a href=&quot;http://sourceforge.net/projects/partcover/&quot;&gt;repository&lt;/a&gt; is no longer being maintained by its original developers and is now being maintained on &lt;a href=&quot;https://github.com/sawilde/partcover.net4&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Using OpenCover&lt;/h3&gt;
&lt;h5&gt;Preparing for OpenCover&lt;/h5&gt;
&lt;p&gt;The following steps detail how to download OpenCover (and other supporting tools) from NuGet.&lt;/p&gt;
&lt;p&gt;OpenCover is available as a zip or msi download via its bitbucket &lt;a href=&quot;https://bitbucket.org/shaunwilde/opencover/downloads&quot;&gt;mirror&lt;/a&gt; but for the sake of this article we will use the OpenCover nuget package.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new solution&lt;/li&gt;
&lt;li&gt;For that solution &amp;quot;Enable NuGet Package Restore&amp;quot;&lt;/li&gt;
&lt;li&gt;Using &amp;quot;Manage NuGet Packages for Solution&amp;quot; add the following packages&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;OpenCover&lt;/li&gt;
&lt;li&gt;ReportGenerator&lt;/li&gt;
&lt;li&gt;NUnit.Runners&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once completed you should have a solution with a .nuget folder which contains a packages.config that looks something like the following&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token prolog&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;packages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;package&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;NUnit.Runners&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2.6.3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;package&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;OpenCover&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;4.5.1923&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;package&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;ReportGenerator&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1.9.1.0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;packages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a C# project (class library) called Sample&lt;/li&gt;
&lt;li&gt;Create a C# project (class library) called Sample.Test and reference the Sample project&lt;/li&gt;
&lt;li&gt;Use NuGet to add the following package&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;NUnit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now to add a simple class and method and a test that will exercise that method.&lt;/p&gt;
&lt;p&gt;In the sample project add the following class&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Target&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DoSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;I ran!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the Sample.Test project add the following class&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;NUnit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Framework&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;TestFixture&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TargetTest&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token attribute&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DoSomethingTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;DoSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Running tests with OpenCover&lt;/h4&gt;
&lt;p&gt;OpenCover does not directly execute your tests but instead needs to execute another application that executes your tests in this case we are using NUnit.&lt;/p&gt;
&lt;p&gt;First lets create a batch file that we can execute our tests from the command line&lt;/p&gt;
&lt;p&gt;......&#92;packages&#92;NUnit.Runners.2.6.3&#92;tools&#92;nunit-console.exe sample.test.dll /noshadow&lt;/p&gt;
&lt;p&gt;This batch file can be added to the Sample.Test project (with Copy to Output Directory set to Copy Always).&lt;/p&gt;
&lt;p&gt;Now we can use OpenCover to execute this batch file, again we can add this as a a batch file to our Sample.Test project so that we can execute it on the command line&lt;/p&gt;
&lt;p&gt;......&#92;packages&#92;OpenCover.4.5.1923&#92;OpenCover.Console.exe -target:runtests.bat -register:user -filter:+[Sample]*&lt;/p&gt;
&lt;p&gt;The arguments are:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-target:&lt;/code&gt; - used to indicate the target process for OpenCover to execute.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-register:user&lt;/code&gt; - used to register the COM objects that OpenCover uses to instrument your assemblies.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-filter:&lt;/code&gt; - used to control which assemblies OpenCover will gather coverage data for. The filter is capable of including and excluding assemblies and classes and is actually the same filter format that PartCover uses. The filter is one of the more complex features of OpenCover and more detail is provided with the documentation that is installed alongside OpenCover or in the Usage wiki.&lt;/p&gt;
&lt;p&gt;When executed, OpenCover will produce an XML file (default results.xml) that contains all the data related to that test run. To visualize that data we can use ReportGenerator to produce some rich HTML output. ReportGenrator can also be run on the command line&lt;/p&gt;
&lt;p&gt;......&#92;packages&#92;ReportGenerator.1.9.1.0&#92;reportgenerator.exe -reports:results.xml -targetdir:coverage&lt;/p&gt;
&lt;p&gt;If we open the produced coverage output (coverage&#92;index.htm) we can see the visualization of the coverage of our target code.
&lt;img src=&quot;https://ucarecdn.com/66675972-3cb5-4e53-bdb8-8295d81ba3e1/Capturecpver.png&quot; alt=&quot;Capture-cpver&quot; /&gt;
As you can see it is quite simple to understand what code your tests actually cover.&lt;/p&gt;
&lt;p&gt;For a real-world example OpenCover is actually used to gather coverage on it&#39;s own tests and the results can be seen on the OpenCover &lt;a href=&quot;https://opencover.atlassian.net/builds/browse/OPC-DEF-40/artifact/JOB1/coverage/index.htm&quot;&gt;build pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;NOTE: This article was originally published on &lt;a href=&quot;https://www.codeproject.com/Articles/677691/Getting-code-coverage-from-your-NET-testing-using&quot;&gt;CodeProject&lt;/a&gt; Nov 3rd 2013&lt;/p&gt;
</description>
      <pubDate>Sun, 03 Nov 2013 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/getting-code-coverage-from-your-net-testing-using-opencover/</guid>
    </item>
    <item>
      <title>Application Tracing</title>
      <link>https://blog.many-monkeys.com/posts/application_tracing/</link>
      <description>&lt;p&gt;So &lt;a href=&quot;https://github.com/sawilde/opencover&quot;&gt;OpenCover&lt;/a&gt; is as feature complete as I care to take it at the moment, I may do this one feature involving &lt;a href=&quot;https://github.com/sawilde/opencover/issues/144&quot;&gt;Windows Store applications&lt;/a&gt; should I have a need for it, and I decided to not continue with &lt;a href=&quot;https://monkey-see-monkey-do-blog.herokuapp.com/2012/02/mutation-testing-use-for-re-jit&quot;&gt;OpenMutate&lt;/a&gt; as I can&#39;t really find a need for it other than an exploratory investigation into reJIT.&lt;/p&gt;
&lt;p&gt;I do have one more itch to scratch when it comes to profilers and that is application tracing and this may allow me to play with other technologies which I&#39;ll list later. This itch started a few months back, perhaps 6+ months ago, when I was trying to integrate some commercial tracing applications to an application I was working on and they both died horribly and I started to look for alternatives and found nothing available. Now I could have started the project then but I decided to pester both vendors until they fixed the problem which they eventually did (within a week or two of each other or so it seemed to me) and I integrated one of the solutions and moved on... but the itch never went away.&lt;/p&gt;
&lt;p&gt;So what am I thinking... well a profiler (obviously) with 32/64 support (again given) and making obscene abuse of the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms231874.aspx&quot;&gt;COR_PRF_MONITOR_ENTERLEAVE&lt;/a&gt; functionality. The problem here is I don&#39;t really know what people will want to track (hey that is why there are companies that do this thing with BAs and such like to decide on this) so in the first instance I&#39;ll go at tracing everything (which will probably be very slow) and go from there.&lt;/p&gt;
&lt;p&gt;This leads to the next problem, data, lots of it, lots and lots of it, and that data is going to need a home but a home I can then use to create reports at some point. For this I am thinking asynchronous, initially a queue and potentially an event source like data store like &lt;a href=&quot;http://geteventstore.com/&quot;&gt;EventStore&lt;/a&gt; or &lt;a href=&quot;https://github.com/NEventStore/NEventStore&quot;&gt;NEventStore&lt;/a&gt;. The advantage of an event source would allow the ability to regenerate the views once we know what they are, perhaps something along the lines of &lt;a href=&quot;http://www.splunk.com/&quot;&gt;Splunk&lt;/a&gt; or &lt;a href=&quot;https://www.splunkstorm.com/&quot;&gt;SplunkStorm&lt;/a&gt; would come into play.&lt;/p&gt;
&lt;p&gt;So a name... always the hardest part but thankfully we have the internet and online dictionaries so I&#39;ve gone with &lt;a href=&quot;https://github.com/sawilde/opendiscover&quot;&gt;OpenDiscover&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Sun, 15 Sep 2013 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/application_tracing/</guid>
    </item>
    <item>
      <title>Creating a simple NodeJS app with Mongo</title>
      <link>https://blog.many-monkeys.com/posts/creating_a_simple_node_js_app_with_mongo/</link>
      <description>&lt;p&gt;Okay, I woke up this morning (6am) with a need to create a simple reporting dashboard to display the coverage results from OpenCover when it dog-foods its own tests. Now that OpenCover has no **_reported _**bugs, I decided to use my spare time to investigate other technologies for a while.&lt;/p&gt;
&lt;p&gt;What I needed was simple &#39;online&#39; storage to capture results from the build system and the ability to extract that data into charts. Normally I&#39;d probably knock up a simple rails app because it is easy to do, however I decided, probably due to the heat, to use the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot;&gt;node.js&lt;/a&gt; - a technology I haven&#39;t used but have meant to for a while; I also like the JavaScript syntax better than ruby (it&#39;s a personal thing)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.mongodb.org/&quot;&gt;mongodb&lt;/a&gt; - a database I am familiar with&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/chart/&quot;&gt;google charts&lt;/a&gt; - free; as in beer.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.heroku.com/&quot;&gt;heroku&lt;/a&gt; - free; well my intended usage will be.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A quick time-boxed search of the web about how to use node with mongodb and create a RESTful API and I settled on the following packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://mongoosejs.com/&quot;&gt;mongoose&lt;/a&gt; - for interacting with the mongo database&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mcavage.github.com/node-restify/&quot;&gt;restify&lt;/a&gt; - for creating a simple rest server&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/remy/nodemon&quot;&gt;nodemon&lt;/a&gt; - monitors changes in your app and restarts; sounds useful&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;ll assume other packages will be added to the mix as challenges present themselves. It&#39;s now 7am and time for breakfast and then the fun starts... And a few hours later we have a simple storage system hosted on heroku all we need now is the chartsThe repository can be found on github. I am sure it will evolve over time but it was very simple to get to this stage by leveraging the work of all those who have gone before.&lt;/p&gt;
</description>
      <pubDate>Sat, 09 Mar 2013 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/creating_a_simple_node_js_app_with_mongo/</guid>
    </item>
    <item>
      <title>MongoDB, Mongoid, MapReduce and Embedded Documents.</title>
      <link>https://blog.many-monkeys.com/posts/mongo_db_mongoid_map_reduce_and_embedded_documents_/</link>
      <description>&lt;p&gt;I am using &lt;a href=&quot;http://mongoid.org/en/mongoid/index.html&quot;&gt;Mongoid&lt;/a&gt; to store some data as documents in a &lt;a href=&quot;http://www.mongodb.org/&quot;&gt;MongoDB&lt;/a&gt; database and then run some &lt;a href=&quot;http://en.wikipedia.org/wiki/MapReduce&quot;&gt;MapReduce&lt;/a&gt; queries against the data. Now I have no trouble with mapping data from normal documents and an embedded document but I could not extract data from an embedded collection of documents i.e.&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;include&lt;/span&gt; Mongoid&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Document

  &lt;span class=&quot;token comment&quot;&gt;#fields&lt;/span&gt;
  field &lt;span class=&quot;token symbol&quot;&gt;:custom_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;String&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;#relations&lt;/span&gt;
  embeds_many &lt;span class=&quot;token symbol&quot;&gt;:bars&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;token command-literal&quot;&gt;&lt;span class=&quot;token command string&quot;&gt;``&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token command-literal&quot;&gt;&lt;span class=&quot;token command string&quot;&gt;``&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token command-literal&quot;&gt;&lt;span class=&quot;token command string&quot;&gt;``&lt;/span&gt;&lt;/span&gt;javascript
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bar&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;include&lt;/span&gt; Mongoid&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Document

  &lt;span class=&quot;token comment&quot;&gt;#fields&lt;/span&gt;
  field &lt;span class=&quot;token symbol&quot;&gt;:custom_field&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;String&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;#relations&lt;/span&gt;
  embedded_in &lt;span class=&quot;token symbol&quot;&gt;:Foo&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First it looks like that we need to run the &lt;strong&gt;map&lt;/strong&gt; part of the MapReduce against the parent document and not the child i.e. &lt;strong&gt;Foo.map_reduce(...)&lt;/strong&gt; will work find documents but &lt;strong&gt;Bar.map_reduce(...)&lt;/strong&gt; does not, however that is not surprising as it is also not possible to count all &lt;strong&gt;Bar&lt;/strong&gt; documents by doing &lt;strong&gt;Bar.all.count&lt;/strong&gt; in the rails console.&lt;/p&gt;
&lt;p&gt;Now a MapReduce query in MongoDB is done as a pair of JavaScript scripts, the first does the map by _emit_ting a mini-document of data and the second that aggregates the data in some manner. So thinking I had a collection (array) my first attempt to map data from the embedded document was this:&lt;/p&gt;
&lt;p&gt;MAP:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bars &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; bar &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bars&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;custom_field&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;REDUCE:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; total &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
total &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; total &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produced an unusual result such that there was only a single aggregated document with a null key and the count was the total number of child documents (summed across all the parents).&lt;/p&gt;
&lt;p&gt;Now I could have just broken the child document out and not embedded it but I didn&#39;t want to break the model over something so trivial that must, in my eyes, be possible.&lt;/p&gt;
&lt;p&gt;After much googling and reading of forum posts, I couldn&#39;t find any samples. I eventually observed of some &#39;unusual&#39; syntax on an unrelated topic which led me to rewrite the &lt;strong&gt;map&lt;/strong&gt; script into this:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bars&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; bar &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bars&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bars&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;bar&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;custom_field&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which produced the expected results. Okay this was probably obvious to anyone who knows MongoDB+MapReduce well but it took me a while to find out and it still isn&#39;t that intuitive, though I think I now know why it is this way, so I thought I&#39;d write it up as a bit of a reference.&lt;/p&gt;
</description>
      <pubDate>Sat, 25 Aug 2012 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/mongo_db_mongoid_map_reduce_and_embedded_documents_/</guid>
    </item>
    <item>
      <title>The &quot;Pigs&quot; and &quot;Chickens&quot; fable</title>
      <link>https://blog.many-monkeys.com/posts/the_pigs_and_chickens_fable/</link>
      <description>&lt;p&gt;I think anyone who is anyone who has heard of Agile and Scrum have heard of the Pigs and Chickens story and how it describes those who are committed to the delivery of the project, as &amp;quot;Pigs&amp;quot;, and those who are just involved, as &amp;quot;Chickens&amp;quot;; if not click on the image below and learn more about it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/The_Chicken_and_the_Pig&quot;&gt;&lt;img src=&quot;https://ucarecdn.com/77c231ae-cbf8-4239-95ed-445403dbeb85/pigsnchickens.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However I was just recently re-reading &amp;quot;&lt;a href=&quot;https://www.amazon.com/Death-March-2nd-Edward-Yourdon/dp/013143635X&quot;&gt;Death March&lt;/a&gt;&amp;quot; by Edward Yourdon (1st Edition) and I came across this response to the parable, in the context of commitment whilst on a death march.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I’m not sure you will find any old pigs in development perhaps more chickens. I think that kind of commitment continues until (inevitably?) you get into the first death march project – then there is a rude awakening. Either the pig realises what’s happening, this is the slaughterhouse! RUN!! Or the pig is making bacon…”&lt;/p&gt;
&lt;p&gt;- Paul Mason (Death March).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I just found it quite amusing and thought I should share...&lt;/p&gt;
</description>
      <pubDate>Fri, 08 Jun 2012 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/the_pigs_and_chickens_fable/</guid>
    </item>
    <item>
      <title>Mutation Testing; a use for re-JIT?</title>
      <link>https://blog.many-monkeys.com/posts/mutation_testing_a_use_for_re_jit_/</link>
      <description>&lt;p&gt;&lt;strong&gt;Where to start...&lt;/strong&gt;
Mutation testing is &lt;a href=&quot;http://en.wikipedia.org/wiki/Mutation_testing&quot;&gt;described&lt;/a&gt; as modifying a program in small amounts and then executing the original &#39;passing&#39; tests that exercise that code and then watching them fail. It is a way of making sure your tests are actually testing what you believe they are testing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setting the stage...&lt;/strong&gt;
So how can we do this with .NET? Well first we need to know what tests execute what code and we can use &lt;a href=&quot;https://github.com/sawilde/opencover&quot;&gt;OpenCover&lt;/a&gt; for that when it is using it&#39;s tracking by test feature. With that feature we can see which tests execute which sequence points and also see what branches were exercised, it is this later information we can take advantage of when creating a mutation testing utility.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;New toys to play with...&lt;/strong&gt;
Now this mutation tester is going to be working at the IL level and as such we could use the JIT (Just-in-time) compilation feature that is used with &lt;a href=&quot;https://github.com/sawilde/opencover&quot;&gt;OpenCover&lt;/a&gt; (and &lt;a href=&quot;https://github.com/sawilde/partcover.net4&quot;&gt;PartCover&lt;/a&gt;). However that would mean a complicated instrumentation that we would then have to control which path we would want to exercise, or we could have simpler instrumentation but that would require the process under test (e.g. nunit, mstest, ...) to be stop and started each time to allow new code to be exercised. With .NET 4.5 (in preview at the time of writing) there is a re-JIT compilation feature that we could use instead and this would allow us to use simple instrumentation without needing to stop and start the process under test. There are a number of &lt;a href=&quot;http://blogs.msdn.com/b/davbr/archive/2011/10/10/rejit-limitations-in-net-4-5.aspx&quot;&gt;limitations&lt;/a&gt; of re-JIT but after reviewing them (several times) I don&#39;t think any are actually show stoppers.&lt;/p&gt;
&lt;p&gt;However to make the Re-JIT useful we need a way of executing a test or tests repeatedly without having to restart the application under test and this isn&#39;t possible with nunit and mstest. However it should be possible to use the test runners from &lt;a href=&quot;http://github.com/continuoustests/AutoTest.Net&quot;&gt;AutoTest.Net&lt;/a&gt; if we host them directly or in a separate process that can be communicated with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A plan...&lt;/strong&gt;
So the flow will be something like this (I wonder how will this will stand up to the test of time) I haven&#39;t looked at the latest profiler API in-depth but documentation on &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/hh362351(v=vs.110).aspx&quot;&gt;MSDN&lt;/a&gt;) and &lt;a href=&quot;http://blogs.msdn.com/b/davbr/archive/2011/10/12/rejit-a-how-to-guide.aspx&quot;&gt;David Broman&#39;s&lt;/a&gt; Blog seem to indicate this should be possible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run OpenCover to produce an XML file with a list of what tests exercised what branches&lt;/li&gt;
&lt;li&gt;For each branch point =&amp;gt;All it needs is a name...All of this will be hosted on GitHub under OpenMutate. Let the games begin....&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Fri, 03 Feb 2012 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/mutation_testing_a_use_for_re_jit_/</guid>
    </item>
    <item>
      <title>Unusual coverage in VB.NET</title>
      <link>https://blog.many-monkeys.com/posts/unusual_coverage_in_vb_net/</link>
      <description>&lt;p&gt;Recently a user posted on &lt;a href=&quot;http://stackoverflow.com/questions/8926063/code-coverage-why-is-end-marker-red-end-if-end-try&quot;&gt;StackOverflow&lt;/a&gt; on why he was seeing unusual coverage results in VB.NET with MSTEST and Visual Studio. The the question already had answers that helped the questioner but I decided to delve a little deeper and find out why the solution proposed worked.&lt;/p&gt;
&lt;p&gt;The issue was that in his code sample the &lt;strong&gt;End Try&lt;/strong&gt; was not being shown as covered even though he had exercised the Try and the Catch parts of his code.&lt;/p&gt;
&lt;p&gt;First I broke his sample down into something simpler and I have highlighted the offending line.&lt;/p&gt;
&lt;pre class=&quot;language-vbnet&quot;&gt;&lt;code class=&quot;language-vbnet&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;Function&lt;/span&gt; Method&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;As&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;Try&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;Return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;Catch&lt;/span&gt; ex &lt;span class=&quot;token keyword&quot;&gt;As&lt;/span&gt; Exception
&lt;span class=&quot;token keyword&quot;&gt;Return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;End&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;Try&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;End&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;Function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In debug we can extract the following sequence points (I am, obviously, using &lt;a href=&quot;https://github.com/opencover/opencover&quot;&gt;OpenCover&lt;/a&gt; for this.)&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoints&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;261&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;32&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;7&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;7&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;262&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;12&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;263&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;22&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;19&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;264&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;30&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;10&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;10&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;20&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;265&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;22&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;11&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;11&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;40&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;266&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;16&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;12&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;12&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;41&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;6&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;267&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;17&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;SequencePoints&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(where sl = start line, el = end line, sc = start column, ec = end column and offset = IL offset in decimal)&lt;/p&gt;
&lt;p&gt;However these only make sense when you look at the IL...&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;.method public static
string Method &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; cil managed
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
// Method begins at RVA 0x272c
// Code size &lt;span class=&quot;token number&quot;&gt;43&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x2b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
.maxstack &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
.locals init &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; string Method,
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; class &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception ex
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

IL_0000: nop
IL_0001: nop
.try
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    IL_0002: ldstr &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    IL_0007: stloc.0
    IL_0008: leave.s IL_0029

    IL_000a: leave.s IL_0028
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end .try
catch &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    IL_000c: dup
    IL_000d: call void &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Microsoft.VisualBasic&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;class &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    IL_0012: stloc.1
    IL_0013: nop
    IL_0014: ldstr &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    IL_0019: stloc.0
    IL_001a: call void &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Microsoft.VisualBasic&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    IL_001f: leave.s IL_0029

    IL_0021: call void &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Microsoft.VisualBasic&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    IL_0026: leave.s IL_0028
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end handler

IL_0028: nop

IL_0029: ldloc.0
IL_002a: ret
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end of method Module1::Method
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now as you can see the End Try line that is causing concern would only be marked as hit (assuming they are using similar instrumentation to OpenCover) if the code reached IL instruction at offset 40 (IL_0028) however when one looks at the IL produced it is not possible to see how you would ever reach that instruction due to the odd IL produced (&lt;a href=&quot;http://en.wikipedia.org/wiki/List_of_CIL_instructions&quot;&gt;&lt;strong&gt;leave.s&lt;/strong&gt;&lt;/a&gt; is a small jump like instruction that is used to exit try/catch/finally blocks) and if you follow the code you see that you will always reach a &lt;strong&gt;leave.s&lt;/strong&gt; that jumps to IL_0029 first.&lt;/p&gt;
&lt;p&gt;In release the IL changes to something more like what I was expecting beforehand and it has no unusual extra IL...&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;.method public static
string Method &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; cil managed
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
// Method begins at RVA 0x2274
// Code size &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x1e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
.maxstack &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
.locals init &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; string Method,
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; class &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception ex
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

.try
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    IL_0000: ldstr &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    IL_0005: stloc.0
    IL_0006: leave.s IL_001c
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end .try
catch &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    IL_0008: dup
    IL_0009: call void &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Microsoft.VisualBasic&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;class &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    IL_000e: stloc.1
    IL_000f: ldstr &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    IL_0014: stloc.0
    IL_0015: call void &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Microsoft.VisualBasic&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    IL_001a: leave.s IL_001c
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end handler

IL_001c: ldloc.0
IL_001d: ret
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end of method Module1::Method
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but so do the sequence points...&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoints&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;33&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;22&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;15&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;34&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;22&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;11&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;11&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;28&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;35&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;17&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;SequencePoints&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now one will never see your try/catch lines marked covered, so this is not helpful.&lt;/p&gt;
&lt;p&gt;So lets try changing your code as suggested and go back to debug (because that is where you will be running coverage from usually.)&lt;/p&gt;
&lt;pre class=&quot;language-vbnet&quot;&gt;&lt;code class=&quot;language-vbnet&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;Function&lt;/span&gt; Method2&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;As&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;Dim&lt;/span&gt; x &lt;span class=&quot;token keyword&quot;&gt;As&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;Try&lt;/span&gt;
    x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;Catch&lt;/span&gt; ex &lt;span class=&quot;token keyword&quot;&gt;As&lt;/span&gt; Exception
    x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;End&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;Try&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;Return&lt;/span&gt; x
&lt;span class=&quot;token keyword&quot;&gt;End&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;Function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again we look at the sequence points...&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoints&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;268&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;33&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;15&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;15&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;269&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;12&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;17&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;17&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;270&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;19&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;18&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;18&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;17&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;271&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;30&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;19&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;19&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;18&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;272&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;19&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;20&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;13&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;20&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;31&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;273&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;16&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;32&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;6&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;274&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;17&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;22&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;22&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SequencePoint&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;36&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ordinal&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;7&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;uspid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;275&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;ec&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;17&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;23&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;sl&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;23&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;SequencePoints&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the IL...&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;.method public static
string Method2 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; cil managed
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
// Method begins at RVA 0x282c
// Code size &lt;span class=&quot;token number&quot;&gt;38&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x26&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
.maxstack &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
.locals init &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; string Method2,
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; string x,
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; class &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception ex
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

IL_0000: nop
IL_0001: nop
.try
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    IL_0002: ldstr &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    IL_0007: stloc.1
    IL_0008: leave.s IL_001f
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end .try
catch &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    IL_000a: dup
    IL_000b: call void &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Microsoft.VisualBasic&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;class &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mscorlib&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;System.Exception&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    IL_0010: stloc.2
    IL_0011: nop
    IL_0012: ldstr &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    IL_0017: stloc.1
    IL_0018: call void &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Microsoft.VisualBasic&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    IL_001d: leave.s IL_001f
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end handler

IL_001f: nop
IL_0020: ldloc.1
IL_0021: stloc.0
IL_0022: br.s IL_0024

IL_0024: ldloc.0
IL_0025: ret
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; // end of method Module1::Method2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So for the &lt;strong&gt;End Try&lt;/strong&gt; to be covered we need line 21 to be hit and that is offset 31 (IL_001F) and as it can be seen both &lt;strong&gt;leave.s&lt;/strong&gt; instructions jump to that point so now that line will be marked as covered.&lt;/p&gt;
</description>
      <pubDate>Sat, 21 Jan 2012 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/unusual_coverage_in_vb_net/</guid>
    </item>
    <item>
      <title>Adding OpenCover to TeamCity</title>
      <link>https://blog.many-monkeys.com/posts/adding_open_cover_to_team_city/</link>
      <description>&lt;p&gt;Adding OpenCover to the latest version of &lt;a href=&quot;http://www.jetbrains.com/teamcity/&quot;&gt;TeamCity&lt;/a&gt; (6.5) couldn&#39;t be easier however if you need help follow these simple steps.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sawilde/opencover/downloads&quot;&gt;Download&lt;/a&gt; and install OpenCover&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://reportgenerator.codeplex.com/&quot;&gt;Download&lt;/a&gt; and install ReportGenerator (actually unzip)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Register the OpenCover profiler DLLs using the regsvr32 utility&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;regsvr32 /s x86&#92;OpenCover.Profiler.dll
regsvr32 /s x64&#92;OpenCover.Profiler.dll&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Using TeamCity add a new Build Step to your configuration&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose C&lt;strong&gt;ommand Line&lt;/strong&gt; as the runner type then choose &lt;strong&gt;Custom Script&lt;/strong&gt; for the Run option.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now all is needed is to set up the command to run the profiler against your tests e.g. for OpenCover the working directory is set to** main&#92;bin&#92;debug** and so we have&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;quot;%env.ProgramFiles(x86)%&#92;opencover&#92;opencover.console.exe&amp;quot; &amp;quot;-target:......&#92;tools&#92;NUnit-2.5.10.11092&#92;bin&#92;net-2.0&#92;nunit-console-x86.exe&amp;quot; -targetargs:&amp;quot;OpenCover.Test.dll /noshadow&amp;quot; -filter:&amp;quot;+[Open*]* -[OpenCover.T*]*&amp;quot; &amp;quot;-output:......&#92;opencovertests.xml&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;quot;%env.ProgramFiles(x86)%&#92;ReportGenerator&#92;bin&#92;ReportGenerator.exe&amp;quot; ......&#92;opencovertests.xml ......&#92;coverage&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Finally setup the artifacts so that you can view the results in TeamCity e.g.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;%teamcity.build.workingDir%&#92;opencovertests.xml
%teamcity.build.workingDir%&#92;coverage&#92;**&#92;*.*&lt;/p&gt;
&lt;p&gt;And there you have it, OpenCover running under TeamCity and visual reports provided by ReportGenerator. I am sure you will find ways to improve upon this for your own builds.&lt;/p&gt;
</description>
      <pubDate>Sun, 02 Oct 2011 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/adding_open_cover_to_team_city/</guid>
    </item>
    <item>
      <title>The problem with sequence coverage. (part 2)</title>
      <link>https://blog.many-monkeys.com/posts/the_problem_with_sequence_coverage_part_2_/</link>
      <description>&lt;p&gt;Previously I mentioned why just relying on sequence coverage is not a good idea as it is possible to have 100% sequence coverage but not 100% code coverage. However I only described a scenario that used a branch that had 2 paths i.e. the most common form of the conditional branches, but there is one other member of the conditional branch family that exists in IL and that is the switch instruction; this instruction can have many paths. This time I am using the code from the &lt;a href=&quot;http://json.codeplex.com/&quot;&gt;Newtonsoft.Json&lt;/a&gt; library because a) it has tests and b) it is very well covered at 83% sequence coverage, but only 72% (by my calculations) branch coverage. The subject of this investigation is BsonReader::ReadType(BsonType) this method has a very large switch statement, that actually is defined as a switch statement in IL, with a default and several &lt;a href=&quot;http://en.wikipedia.org/wiki/Switch_statement&quot;&gt;fall-throughs&lt;/a&gt;; a fall-through is where two or more case statements call the same code. The method itself has 98% sequence coverage and 82% branch coverage; the only code that is uncovered is the handler for the &lt;strong&gt;default:&lt;/strong&gt; path.
&lt;img src=&quot;https://ucarecdn.com/cf29e028-0695-4a39-8239-b73b402aa34f/seq_2_code.png&quot; alt=&quot;seq_2_code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;which is not unexpected as it is a handler for an Enum which should not be set to any value that is not part of the allowed values. Looking at the branch coverage report we have the following results (the switch instruction we are interested in is at IL offset 8.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/7da15aa1-6d0c-4f1c-9ea6-f32e4909b9f8/seq_2_output.png&quot; alt=&quot;seq_2_output&quot; /&gt;
Now the first path (0) is unvisited, but we knew that, so the next unvisited branch is #14 and the next is #17; luckily for us the enum in question that is used by the switch instruction is well defined.
&lt;img src=&quot;https://ucarecdn.com/f34c6e2b-386a-4329-9ae7-2a021aecdb90/seq_2_enum.png&quot; alt=&quot;seq_2_enum&quot; /&gt;
And as such we can thus deduce that the method is never called during testing with the values Symbol and TimeStamp but the code that they would call is covered; in fact we can see from the code that both these enum values are part of the switch/case statement and are part of fall-throughs. So again we see how branch coverage helps identify &#39;potential&#39; issues and test candidates.&lt;/p&gt;
</description>
      <pubDate>Sat, 27 Aug 2011 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/the_problem_with_sequence_coverage_part_2_/</guid>
    </item>
    <item>
      <title>The problem with sequence coverage.</title>
      <link>https://blog.many-monkeys.com/posts/the_problem_with_sequence_coverage_/</link>
      <description>&lt;p&gt;Sequence coverage is probably the simplest coverage metric, the information is packaged in PDB files and can be read using tools like &lt;a href=&quot;http://www.mono-project.com/Cecil&quot;&gt;Mono.Cecil&lt;/a&gt;, but just because a method has 100% sequence coverage does not mean you have 100% code coverage.&lt;/p&gt;
&lt;p&gt;I&#39;ll use an example from OpenCover&#39;s own dogfood tests to demonstrate what I mean. Here is a method which shows that it has 100% coverage (sequence point that is).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/da2934f0-1561-4213-9847-83310ef65a04/seq_1_code.png&quot; alt=&quot;seq_1_code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;However I see an issue and that is that on line 101 there is a condition, i.e. a branch, and yet if the visit count is 1 then there is no possibility that both paths for that branch could have been tested. We can therefore infer that even if we had 10000 visits there is no guarantee that every path would be covered even in such a simple method.&lt;/p&gt;
&lt;p&gt;Looking at the OpenCover results from which the coverage report was generated. We get&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ucarecdn.com/27ac83af-34a5-4ee2-99d3-ed1aef4f80ec/seq_1_output.png&quot; alt=&quot;seq_1_output&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We can see that each sequence point has been visited once, however the branch coverage shows that only one of the paths for the condition we have identified had been visited (in this case it is the true path); which is good as that is what we deduced.So if you are using code coverage tools do NOT just rely on sequence point coverage alone to determine how well covered your code is. Luckily OpenCover now, as of 25th Aug 2011, supports branch coverage and ReportGenerator 1.2 displays most of the information to help you identify possible coverage mismatches.&lt;/p&gt;
</description>
      <pubDate>Thu, 25 Aug 2011 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/the_problem_with_sequence_coverage_/</guid>
    </item>
    <item>
      <title>OpenCover Performance Impact (part 2)</title>
      <link>https://blog.many-monkeys.com/posts/open_cover_performance_impact_part_2_/</link>
      <description>&lt;p&gt;I think I now have a handle on why I was getting the results I earlier reported i.e. &lt;a href=&quot;https://github.com/sawilde/opencover&quot;&gt;OpenCover&lt;/a&gt; and &lt;a href=&quot;https://github.com/sawilde/partcover.net4&quot;&gt;PartCover&lt;/a&gt; were not some magical performance boosters that added Go Faster stripes to your code.&lt;/p&gt;
&lt;p&gt;After a heads up by leppie and his investigations of using OpenCover on his IronScheme project I realised that I needed to spend some time on optimizing how I get data from the profiler and aggregate it into the report. In case you are wondering IronScheme test that took just shy of 1 minute to run on my machine took over 60mins when running under the profiler, Ouch!&lt;/p&gt;
&lt;h5&gt;The problem&lt;/h5&gt;
&lt;p&gt;First of all I should explain what sort of data OpenCover gathers (and why) and then I can describe what I did to improve performance. OpenCover records each visit to a sequence point and stores these visits into shared memory; I did it this way as I am hoping to be able to use the order of visits for some form of path coverage analysis at a later date. After 8000 visits it informs the host process that there is a block ready for processing. The host takes this block, makes a copy, releases the shared memory back to the profiler and then processes the data. After processing the data the hosts then waits for the next message. It was this latter stage that was the bottleneck as the host was spending too much time aggregating the data that the profiler was already ready with the next 8000 points.&lt;/p&gt;
&lt;h5&gt;An (interim) solution&lt;/h5&gt;
&lt;p&gt;I say interim solution as I am not finished with performance improvements yet but decided that what I had implemented so far was okay for release.
First I looked at how the results were being aggregated and noticed that a lot of the time was being spent looking up the sequence points so that the visit count could be updated, I switched this to a list and mapped the visit count data to the model at the end of the profiling run. This helped but only by bringing the profiling run down to ~40mins.&lt;/p&gt;
&lt;p&gt;I realised that I just had to get the data out of the way quickly and process it at a later date, so I added a processing thread and a ConcurrentQueue. This was an interesting turn of events as the target process now finished in 4 mins but the host took nearly 40 mins to process the data and the memory usage went up to 2.5GB and a backlog of 40K messages. Hmmm....&lt;/p&gt;
&lt;p&gt;After some toying, whilst looking for inspiration, I noticed that the marshaling of the structure (2 integers) was where most of the time was spent. I switched this to using BitConvertor, which also meant that I could avoid the memory pinning required by the marshaling. Now the target process still ran in just under 4 mins but the backlog very rarely reached 20 messages and memory usage stayed at a comfortable level (&amp;lt;100MB) I decided this was enough for now and released a version of the profiler.&lt;/p&gt;
&lt;h4&gt;But what about the earlier results?&lt;/h4&gt;
&lt;p&gt;Those earlier results though were still are cause for thought. Why should the OpenCover dogfood tests be faster but the ironscheme test be so much slower. Well the IronScheme tests were doing a lot of loops and were running parts of the code many 1000&#39;s of times whereas the dogfood tests were unit tests and the code was only being run several times before moving onto the next test fixture and next section of code. I am now thinking that the issue is due to the optimization that is normally performed by the JIT compiler, but is turned off by the profiler i.e. when running the tests (without profiler) the JIT compiler spends time optimizing the code but the time spent is not recovered as the code is not run enough times to get a net gain, compared to when the JIT compiler just compiles the non-optimised modified code that the profiler produces.&lt;/p&gt;
&lt;p&gt;So in conclusion you may see some speed improvements if running tests where your code is only visited a few times but if you are doing intensive execution of code then don&#39;t be surprised if the performance is degraded.&lt;/p&gt;
</description>
      <pubDate>Wed, 10 Aug 2011 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/open_cover_performance_impact_part_2_/</guid>
    </item>
    <item>
      <title>OpenCover Performance Impact</title>
      <link>https://blog.many-monkeys.com/posts/open_cover_performance_impact/</link>
      <description>&lt;p&gt;So how does OpenCover&#39;s profiling impact your testing. The best way is to get some figures so that you can judge for yourself.&lt;/p&gt;
&lt;p&gt;I decided to use OpenCover&#39;s own tests and use the timing value produced by Nunit itself; just like I&#39;d expect any user who is trying to determine impact I suppose. I&#39;ve also added the results from PartCover for comparison. Before I took any numbers I (warmed) the code by running the code several times beforehand.&lt;/p&gt;
&lt;p&gt;Nunit32&lt;/p&gt;
&lt;p&gt;Nunit32 (OpenCover)&lt;/p&gt;
&lt;p&gt;Nunit32 (PartCover)&lt;/p&gt;
&lt;p&gt;Nunit64&lt;/p&gt;
&lt;p&gt;Nunit64 (OpenCover)&lt;/p&gt;
&lt;p&gt;2.643&lt;/p&gt;
&lt;p&gt;2.691&lt;/p&gt;
&lt;p&gt;2.639&lt;/p&gt;
&lt;p&gt;4.544&lt;/p&gt;
&lt;p&gt;3.807&lt;/p&gt;
&lt;p&gt;2.629&lt;/p&gt;
&lt;p&gt;2.69&lt;/p&gt;
&lt;p&gt;2.611&lt;/p&gt;
&lt;p&gt;4.426&lt;/p&gt;
&lt;p&gt;3.753&lt;/p&gt;
&lt;p&gt;2.642&lt;/p&gt;
&lt;p&gt;2.638&lt;/p&gt;
&lt;p&gt;2.612&lt;/p&gt;
&lt;p&gt;4.46&lt;/p&gt;
&lt;p&gt;4.036&lt;/p&gt;
&lt;p&gt;Average&lt;/p&gt;
&lt;p&gt;2.638&lt;/p&gt;
&lt;p&gt;2.673&lt;/p&gt;
&lt;p&gt;2.621&lt;/p&gt;
&lt;p&gt;4.477&lt;/p&gt;
&lt;p&gt;3.865&lt;/p&gt;
&lt;p&gt;I don&#39;t know how to interpret these results as they don&#39;t make much sense, OpenCover seemed to add on average 1.3% to the total time (which I&#39;d expect), whereas PartCover appears to make the code go faster by 0.64%. I can&#39;t explain why the results for 64 bit seem to show that OpenCover improves performance by 13.6%.&lt;/p&gt;
&lt;p&gt;I tried to come up with a number of reasons for the above but the results I keep getting are reasonably consistent, so I decided to post them anyway and perhaps someone else will be able to tell me what is happening.&lt;/p&gt;
</description>
      <pubDate>Sun, 24 Jul 2011 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/open_cover_performance_impact/</guid>
    </item>
    <item>
      <title>Questions about open source and liability in the workplace</title>
      <link>https://blog.many-monkeys.com/posts/questions_about_open_source_and_liability_in_the_workplace/</link>
      <description>&lt;p&gt;Last weekend I attended DDDSydney and one of the most interesting sessions was a panel session about Microsoft and Opensource (Open Source &amp;amp; Microsoft Ecosystem); though as these things go, it went quickly off(ish) topic as expected by the panelists whom I&#39;ll refer to as the crazy drupal girl and the 3 stooges (honestly no offence folks, it was highly entertaining).&lt;/p&gt;
&lt;p&gt;However it got me thinking about the number of projects where I come have across an unusual bit of open source software that has some use (but has not found a niche or has since been surpassed) and I find that this was introduced by a developer as it was their pet open source project. Now the first question is &amp;quot;what is the liability under this scenario?&amp;quot;&lt;/p&gt;
&lt;p&gt;Did the developer ask first as they should before using any open source software on a project? If so then the company accepted the situation but what happens if they did not (or what not made aware) are they still liable or is the developer liable? I assume it would be the company as they should be having some sort of oversight but for small overworked teams where process may not be as strong this may get overlooked.&lt;/p&gt;
&lt;p&gt;The other issue is what happens if you introduce your pet open source software project and then you leave, who supports it? How do you separate the open source project needs and the day-job, when they are so intermingled? Does the remaining team support it, do they have the skills? What happens if the parting was acrimonious in nature then they, the team, raised a legitimate issue would you fix it, or leave them to stew?&lt;/p&gt;
&lt;p&gt;I don&#39;t have answers to the above, I did title this &amp;quot;Questions about...&amp;quot;, that can be applied universally the answer to most I suppose is &amp;quot;it depends&amp;quot;. Each situation will be different I suspect but I think these type of questions should be asked by any company hoping to use open source software and developers wishing to introduce it, whether that are contributors or not.&lt;/p&gt;
&lt;p&gt;Personally I have decided to NOT introduce the open source software I develop into my workplace, yes they could use it and find it useful but they can also afford commercial alternatives. If someone else suggested it, I&#39;d have to make sure there was an agreement should an issue arise that affects them, that if they want it fixed quick then I may have to use &#39;work&#39; time i.e. no guarantees that it would be done that evening or even that week; after all it is supposed to be fun and not stressful.&lt;/p&gt;
</description>
      <pubDate>Sat, 09 Jul 2011 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/questions_about_open_source_and_liability_in_the_workplace/</guid>
    </item>
    <item>
      <title>How do we get Users out of [open source] Welfare?</title>
      <link>https://blog.many-monkeys.com/posts/how_do_we_get_users_out_of_open_source_welfare_/</link>
      <description>&lt;h3&gt;How do we get Users out of [open source] Welfare?&lt;/h3&gt;
&lt;p&gt;Okay an odd title but something I&#39;ve been thinking about for some time and I suppose is the source of much frustration I have been having whilst maintaining &lt;a href=&quot;https://github.com/sawilde/partcover.net4&quot;&gt;PartCover&lt;/a&gt;; I am hoping to reverse the situation with &lt;a href=&quot;https://github.com/sawilde/opencover&quot;&gt;OpenCover&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Categorizing open source users&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First I&#39;d like to explain that I like to roughly categorize people involved in open source like thus:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Contributors&lt;/em&gt; - these are the guys and gals at the pit-face, developing software, writing documentation and generally striving to make an open source product better.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Investors&lt;/em&gt; - these individuals use open source software and help to make the product better via feedback and raising, and following up, issues (probably as it is in their interest to do so).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Benefactors&lt;/em&gt; - usually companies that give tools to open source developers or sponsor a project in other ways i.e. free licenses or free hosting e.g. NDepend, JetBrains and GitHub.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Angels&lt;/em&gt; - these people provide invaluable advice in just managing a open source project and may not be actively involved in the development itself but just keep you sane.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Community&lt;/em&gt; - Our main user base, users of open source but don&#39;t actively contribute back and hence why sometimes I refer to them as Welfare. Maybe in the case of the this group it is just a failure to engage, the product just works and they have no need to be involved outside of viewing forums and stackoverflow. But I feel that without the involvement of this group a lot of open source software, no matter how good, can fall by the wayside.&lt;/p&gt;
&lt;p&gt;But how do we get them involved? Well first we have to find them, in my case with PartCover as the project had been abandoned the users stopped raising issues on the SourceForge forums and tended to ask questions on other outlets such as StackOverflow, SharpDevelop or Gallio forums and mailing lists.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Finding the users&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I scoured the internet and compiled a list of popular places that PartCover was mentioned or supported. I was surprised to find that PartCover was used or supported by SharpDevelop, TeamCity and TypeMock amongst others (and yet again I am surprised it was abandoned and not adopted by anyone sooner).&lt;/p&gt;
&lt;p&gt;StackOverflow seems to be the main place where people ask questions and to keep track of questions I have subscribed to an RSS feed for the partcover tag; and as soon as an opencover tag becomes available, or I get enough rep to create it, I&#39;ll subscribe to that.&lt;/p&gt;
&lt;p&gt;Twitter is also quite a common medium nowadays so I have also set up the following search filter &amp;quot;opencover OR partcover -rt -via&amp;quot; to see if anyone mentions either of the projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Engaging the users&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now I have found the users, or the majority of, I started notifying these lists, forums and projects that PartCover was alive again (and I have started to do the same to inform them about OpenCover). Hopefully bringing them back or at least notifying them that if they have really big issues there is somewhere to go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Involving the Community users&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is the big ask and I don&#39;t have an answer. If the product works then they don&#39;t need to talk to the forums or declare their appreciation of a job well done. I think sites like ohloh are trying to address the balance. Some OS projects have a donate button, but I am not sure we are doing open source for money, though some projects do eventually go commercial, anyone else can pick up the original code and develop it. Maybe the users don&#39;t know how to be involved, in the case of my OS projects they are quite specialised and the learning curve may be too much for some. But I don&#39;t think you have to just be involved in projects you use a lot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Possible ways to get involved&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you are good at graphics why not offer to knock up some graphics for use on web-sites and in the application. [I am quite lucky that Danial Palme added support for PartCover and OpenCover to his Report Generator tool and has done a much better job than I would ever do.]&lt;/p&gt;
&lt;p&gt;If you are good at installers, or even if you want to learn more about them, offer to manage them on behalf of the project.If there is a project you like, support them on the forums like StackOverflow and help other users.&lt;/p&gt;
&lt;p&gt;Perhaps update the wikis and forums, sometimes the users know how a product works or can be used better then the developers.&lt;/p&gt;
&lt;p&gt;If your company uses a lot of open source, why not buy some licenses for useful software tools and donate them, geeks love shiny new toys; quite a few vendors such as NDepend will donate licenses to open source projects.&lt;/p&gt;
&lt;p&gt;If you have an issue, try to help the developers as much as possible to resolve it by supplying as much information as you can and repeatable samples, remember the developers are international and doing this in their own time (as you probably know trying to repeat a scenario from scant information is very frustrating) and maintain contact whilst it is being resolved and let them know when it is.&lt;/p&gt;
&lt;p&gt;Okay that&#39;s me done on the subject for now, suggestions anyone?&lt;/p&gt;
</description>
      <pubDate>Sat, 25 Jun 2011 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/how_do_we_get_users_out_of_open_source_welfare_/</guid>
    </item>
    <item>
      <title>OpenCover First Beta Release</title>
      <link>https://blog.many-monkeys.com/posts/open_cover_first_beta_release/</link>
      <description>&lt;h3&gt;OpenCover First Beta Release&lt;/h3&gt;
&lt;p&gt;Okay, the first post on a blog I created many, many months ago and still not got round to starting. Why the delay? Well, just been busy and not a lot to say; actually some would say I have too much to say it&#39;s just not publishable.&lt;/p&gt;
&lt;p&gt;But now I am happy to announce that the first release of OpenCover is now available on &lt;a href=&quot;https://github.com/sawilde/opencover/downloads&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;quot;So what?&amp;quot; I hear you say, &amp;quot;we have NCover, dotCover and PartCover [and probably many others with the word cover in the name,] do we need another code coverage tool?&amp;quot; Well, I think the answer is &amp;quot;Yes!&amp;quot; but before I say why a brief history.&lt;/p&gt;
&lt;p&gt;About a year ago I adopted PartCover when I found it lost and abandoned and only supporting .NET2; also PartCover has a large user base, SharpDevelop, Gallio, to name but two, and I felt it was a shame to just let it fall by the wayside. I had also done some work on CoverageEye (another OpenSource tool that was originally hosted on GotDotNet and has since vanished) whilst working for a client in the UK, so I felt I had a fighting chance to do the upgrade to .NET4; I don&#39;t know if my changes ever got uploaded to GotDotNet as I was not in charge of that.&lt;/p&gt;
&lt;p&gt;The adoption was far from easy for a number of reasons, one of which was I was surprised just how little C++ I could actually remember and it&#39;s changed a bit since I last used it in anger. Also due to lack of communication with the original developers meant that I was on my own in working out a) how it worked and b) just what the issues are (a lot of the reported issues had long since been abandoned by the reporters).&lt;/p&gt;
&lt;p&gt;At the beginning of the adoption I cloned the SourceForge repository to GitHub, git being the in-thing at the time, and after I was eventually admitted access to SourceForge I attempted to maintain both repositories. Due to the lack of permissions on SourceForge, no matter how many times I asked, I eventually abandoned SourceForge and kept all development to GitHub; I also updated the SourceForge repository with a lot of ReadMe posts to point to GitHub.&lt;/p&gt;
&lt;p&gt;So upgrading PartCover progressed and thankfully bloggers such as &lt;a href=&quot;http://blogs.msdn.com/b/davbr/&quot;&gt;David Broman&lt;/a&gt; had already covered the subject matter about upgrading .NET2 profilers to .NET4 and things to look out for. That, it would turn out, was the easy bit.&lt;/p&gt;
&lt;p&gt;PartCover had 3 main issues (other than lack of .NET4 support)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;64 bit support&lt;/li&gt;
&lt;li&gt;If the target crashed then you got no results.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&#39;ll tackle each of these in turn:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Memory - PartCover builds a model of each assembly/method/instrumented point in memory; though I managed to cut down memory usage by moving some of the data gathering to the profiler host it wasn&#39;t enough - PartCover also added 10 IL instructions (23 bytes) for each sequence point identified + 4 bytes allocated memory for the counter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;64 bit support - PartCover used a complex COM + Named Pipe RPC, which thankfully just worked but I couldn&#39;t work out how to upgrade it to 64 bit (a few other helpers have offered and then gone incommunicado, I can only assume the pain was too much).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Crashing == no results - this was due to the profiler being shutdown unexpectedly and the runtime not calling the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms230217.aspx&quot;&gt;::Shutdown&lt;/a&gt; method and as such all that data not being streamed to the host process; thankfully people were quite happy to fix crashing code so not a major issue but still an annoyance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of this would take major rework of substantial portions of the code and the thought was unbearable. I took a few stabs at bits and pieces but got nowhere.&lt;/p&gt;
&lt;p&gt;Thankfully I had received some good advice and though I tried to apply it to PartCover I realised the only way was to start again, taking what I had learned from the guys who wrote PartCover and some ideas I had come across from looking at other opensource tools such as CoverageEye and Mono.Cecil.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenCover was born.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This time I created a simple COM object supporting the interfaces and then made sure I could compile it in both 32 and 64 bit from day one.&lt;/p&gt;
&lt;p&gt;I then decided to make the profiler as simple as possible, so it is maintainable and move as much of the model handling to the profiler host, thank heavens for &lt;a href=&quot;https://github.com/jbevain/cecil&quot;&gt;Mono.Cecil&lt;/a&gt;. The only complex thing was deconstructing the IL and reassembling it after it had been instrumented. OpenCover only inserts 3 IL instruction (9/13 bytes depending on 32/64 bit) per instrumented point; it forces a call into the profiler assembly itself and this C++ code then records the &#39;hit&#39;.&lt;/p&gt;
&lt;p&gt;Finally I decided I had to get the data out of the profiler and into the host as soon as possible. I toyed with WCF and WWSAPI but this also meant I had no XP support, but at least I could test other ideas. However if my target/profiler crashed I would loose the last packet of data; not drastic but not ideal. Eventually I bit the bullet and switched to using shared memory.&lt;/p&gt;
&lt;p&gt;The switch to shared memory has brought a number of benefits one of which is the ability to handle a number of processes under the same profiling session, both 64 and 32 bit and to aggregate the results as they all use the same shared memory. I have yet to work out how to set this up via configuration files but anyone wishing to experiment can do so via modifying the call to ProfilerManager::RunProcess in the OpenCover.Host::Program.&lt;/p&gt;
&lt;p&gt;So this is where we are now, OpenCover has been released (beta obviously) and as of time of writing some people have actually downloaded it. I am now braced for the issues to come flooding/trickling in.&lt;/p&gt;
&lt;p&gt;Feel free to download and comment, raise issues on GitHub, get involved; Daniel Palme, he of &lt;a href=&quot;http://reportgenerator.codeplex.com/&quot;&gt;Report Generator fame&lt;/a&gt;, is hopefully going to upgrade his tool to include OpenCover. OpenCover First Beta Release&lt;/p&gt;
</description>
      <pubDate>Sat, 18 Jun 2011 00:00:00 GMT</pubDate>
      <dc:creator></dc:creator>
      <guid>https://blog.many-monkeys.com/posts/open_cover_first_beta_release/</guid>
    </item>
  </channel>
</rss>