<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title></title>
        <link>undefined</link>
        <description>undefined</description>
        <lastBuildDate>Wed, 19 Apr 2023 09:20:14 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>Joplin Pages Publisher</generator>
        <item>
            <title><![CDATA[Building a new beer store]]></title>
            <guid>69a47e494834443eaf36df549bf148a7</guid>
            <pubDate>Mon, 24 Jan 2022 16:07:14 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>As part of our ongoing efforts to improve the pub, we needed more space to store our beer.</p>
<h2 id="a-small-space">A small space</h2>
<p>For years, we’ve struggled with an undersized cold store for our beer. When I say undersized, what I mean is that we are constantly brewing “just in time” to ensure there’s enough space for the newly brewed beer. The beer store can hold a maximum of about two brews of beer.</p>
<p>Because the beer store is so small, whenever a new batch of beer is ready, we have to unload everything to get the new stuff in. This is basic stock rotation. However, when you’re dealing with 9, 18 and 36 gallon barrels, this can be a lot of hard, heavy lifting.</p>
<p>In addition to all this work rotating stock, the lack of space means we are limited to what we can brew. It makes it difficult for us to make a strong dark winter special, ideally brewed months in advance, because of the precious space it occupies. It also means that our brew schedule is strictly dictated by demand from the pub. Planning around this and taking holiday is hard.</p>
<h2 id="towards-a-solution">Towards a solution</h2>
<p>For the last year or so, we’ve been thinking seriously about what could be done. My father’s workshop, located next to the brewery, seemed to be the ideal space. It receives a lot less direct sun than the current beer store, and has the potential to be much better insulated. It just needed decluttering. Years of accumulated odds and sods from the pub and brewery needed organising, giving away, selling, throwing away, repurposing. Over the course of several weeks in autumn 2021 we did this, and at the same time we planning how to use the space.</p>
<p>Between the brewery team, we came up with a plan to split the space into thirds, allowing the leftmost third as space for the cold store.</p>
<p>Peter Fisher from ACM Ltd, based in Norwich, came to visit us and from our conversations sketched a design.</p>
<p><img src="/_resources/1b7bf1c49b774ef2b7117fb11ce182a5.png" /></p>
<p>We sat on this, happy with the design. The quote seemed reasonable, but was on the high end of what we were able to afford. We were trying to figure out how to make it work.</p>
<h2 id="a-timely-email">A timely email</h2>
<p>Then in September, through Bungay Events and Business Association, I received an email advising me that East Suffolk Council had launched a new grant for businesses affected by Covid-19 restrictions. This “Plan for the Future” grant scheme seemed to be a really good match for our beer store project:</p>
<blockquote>
<p>Businesses which are looking to bring forward investment projects that will have a significant impact on their business will be able to apply for grants of between £5,000 and £25,000 to help support their projects.</p>
</blockquote>
<p>I sent an email to East Suffolk council and within hours Margaret Oakley at the New Anglia Growth Hub had responded with some registration forms, helpfully partially completed based on the information they already held about us. The forms themselves do ask for quite a bit of detail, but Margaret responded very quickly to all my queries.</p>
<p>By the following day the registration forms had been completed I was assigned a growth advisor, Robert Turnbull, also at the New Anglia Growth Hub. Robert called me that day, and we had a long chat about the project. Robert listened carefully and was able offer excellent advice on how to complete the application form. Again, the form required some technical detail, and in every case Robert was able to provide a clear and concise answer on how to complete it.</p>
<p>Over the course the next few weeks, working through the details of the application form - figures from my accountant, how much state aid we’d already received, turnover, balance sheet, etc - I finally managed to complete the final bits and submit our application on October 1st. A couple of weeks later, on the 15th of October, our application was approved!</p>
<h2 id="a-small-rethink">A small rethink</h2>
<p>Once the grant application was approved, we knew we’d be okay to schedule the work.  With that in mind, we had another look at our plans.</p>
<p>A local refrigeration engineer, and a regular at the pub, Bo came to look at the space. Bo is an expert in this field and has been working with refrigerated spaces for years. He advised us to try to envisage exactly how we would use the cold room. This exercise proved invaluable.</p>
<p>Along with my father, Digby and Luke, we started pacing the space out, laying it out with masking tape on the floor, shifting versions of where the barrels would go.</p>
<p>One of the biggest problems with the existing beer store is that once it starts to get full, there’s really no room to move around. When we started looking at the space with these barrels in place, we realised that having 3 sliding doors would not only overcomplicated things, it resulted in multiple “channels” that did not make the best use of the space.</p>
<p>After thinking things through, we asked Peter to come back and consider a plan using the rear half of the workshop instead of just the leftmost third. This would mean we could get away with only one large sliding door instead of three smaller ones, and would give us a lot more usable space. In retrospect, I believe this was the correct choice - it’s a much better design overall.</p>
<h2 id="a-job-well-done">A job well done</h2>
<p>In the second week of December, ACM send their team to install the cold room. They work very quickly and professionally, completely nearly all of the work in 2 days. A week later, Beeline Refrigeration come and install the cooler and LED illumination. The only thing left to install is the door, a 1500mm wide custom built sliding door made from foam covered with sheet steel and PVC. ACM return a few days later and install it.</p>
<p>Overall, I’m very happy with the result. The workmanship is of the highest quality and the additional breathing room it gives us means that there is much less work moving barrels as part of the stock rotation. Now, with the larger beer store, we can potentially look at slightly increasing production - perhaps producing a kegged product to sit alongside the craft kegged beers that we have been buy in as part of our ever-changing craft beer selection at the pub. This will not only make us more competitive, but will create a product that’s brewed onsite instead of couriered to the pub.</p>
<p>Thanks  to East Suffolk for the Plan to the Future Grant, and the New Anglia Growth Hub for being so helpful during the application process. Thanks to ACM and Beeline for their patience and professionalism throughout the build process.</p>
<p><img src="/_resources/3883f2db5a134606a52ce9c6c2cbb009.png" /></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Airack glass dryer]]></title>
            <guid>f7f5add4c6674153be971ba0b75962bb</guid>
            <pubDate>Mon, 10 Jan 2022 09:29:39 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>In April 2021, at great expense, we bought an Airack glass dryer for the pub. This was after months or years of mysteriously occasionally flat-looking pints of lager. The topic comes up frequently on the Pub Owner’s Network, and one of the common responses suggests buying an Airack. They’re expensive - around £500.</p>
<p>After a series of experiments which involved pouring lager into a series of wet, dry, and nearly dry glasses. We tried varying the temperature of the glass. What we found was that unless the glass is completely dry, the nucleation site at the bottom can sometimes (but not always) fail to produce bubbles. The effect is most pronounced in tall, narrow “continental” style glasses, which presumably dry slower due to reduced air flow. We tried briefly using a battery-powered fan to dry the glasses with limited success.</p>
<p><img src="/_resources/63d5338b495946c089a354dfb1ce4dfb.png" /></p>
<h2 id="enter-the-airack">Enter the Airack</h2>
<p>Enter the <a title="https://airack.co.uk/" href="https://airack.co.uk/">Airack by Clenaware Systems</a>, a box with a fan and a bunch of holes. You put the glasses on top, twist a timer knob, and ambient temperature air is blown into the glasses. After about 5 minutes, they’re completely dry.</p>
<p>The short story is that it works. We haven’t had any problems with lager since. The downside is that it’s a relatively expensive machine: we paid <a title="https://www.barcare.co.uk/airack-45-lite-glass-dryer.html" href="https://www.barcare.co.uk/airack-45-lite-glass-dryer.html">£509.99 including VAT and delivery from Barcare Supreme Limited</a>. It comes with a 1 year warranty on parts and labour, although I’m led to believe that Airack will increase their warranty to 2 years if you leave a Google review.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Handling rejected promises in Express.js requests]]></title>
            <guid>69d370f7c48048d2b26623e3c14ab3b1</guid>
            <pubDate>Sat, 01 Jan 2022 21:37:16 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>In 2015, JavaScript introduced <code>async</code> keyword which allows functions to <code>await</code> on promises, causing execution of the current context to pause until the promise <code>resolves</code> or <code>rejects</code>. The older way of handling promises them using <code>then</code> and <code>catch</code> introduced an additional level of nesting.</p>
<p>It’s reasonable to expect that Express handles traditional errors and rejected promises (and thrown errors within an async function) the same way. Unfortunately, Express v4 has a <em>gotcha</em> where rejected promises in an async function require additional treatment.</p>
<h2 id="synchronous-errors">Synchronous errors</h2>
<p>In the following typical Express request handler, the <code>doSomething</code> function throws an error.</p>
<div><pre class="hljs"><code>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">"/sync-example"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-title function_">doSomething</span>();
  res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>(<span class="hljs-string">"OK"</span>);
});</code></pre></div>
<p>What happens when a client makes a request to this endpoint?</p>
<div><pre class="hljs"><code>curl -v localhost:3000/sync-example
*   Trying ::1:3000...
* Connected to localhost (::1) port 3000 (#0)
<span class="hljs-meta">&gt;</span> <span class="language-javascript"><span class="hljs-variable constant_">GET</span> /sync-example <span class="hljs-variable constant_">HTTP</span>/<span class="hljs-number">1.1</span></span>
<span class="hljs-meta">...</span>
<span class="hljs-meta">&gt;</span>
* Mark bundle as not supporting multiuse
&lt; HTTP/1.1 500 Internal Server Error
<span class="hljs-meta">...</span>
&lt;
<span class="hljs-meta">...</span> <span class="language-javascript"><span class="hljs-title class_">Stack</span> trace rendered <span class="hljs-keyword">as</span> <span class="hljs-variable constant_">HTML</span> ...</span>
* Connection #0 to host localhost left intact</code></pre></div>
<p>The following happens:</p>
<ol>
<li>The server responds with a 500 error.</li>
<li>The client receives a stack trace rendered as HTML.</li>
<li>The server continues serving request.</li>
</ol>
<p>Note that setting <code>NODE_ENV</code> to <code>production</code> causes Express to return less verbose error messages.</p>
<h2 id="asynchronous-errors">Asynchronous Errors</h2>
<p>What happens when we try the same thing with an asynchronous request handler?</p>
<p>Express request handlers are just functions, so of course it is possible to use an <code>async</code> function as a request handler:</p>
<div><pre class="hljs"><code>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">"/async-example"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">await</span> <span class="hljs-title function_">asyncDoSomething</span>();
  res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>(<span class="hljs-string">"OK"</span>);
});
</code></pre></div>
<p>When I tested, using Node v17.3.0 and Express 4.17.1, Node crashed with the following error:</p>
<div><pre class="hljs"><code><span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/i</span>ndex-<span class="hljs-number">2</span>.js:<span class="hljs-number">22</span>
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error(<span class="hljs-string">"Something went wrong."</span>);
        ^

Error: Something went wrong.
    at asyncDoSomething (<span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/i</span>ndex-<span class="hljs-number">2</span>.js:<span class="hljs-number">22</span>:<span class="hljs-number">9</span>)
    at <span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/i</span>ndex-<span class="hljs-number">2</span>.js:<span class="hljs-number">26</span>:<span class="hljs-number">9</span>
    at Layer.handle [as handle_request] (<span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/</span>node_modules<span class="hljs-regexp">/express/</span>lib<span class="hljs-regexp">/router/</span>layer.js:<span class="hljs-number">95</span>:<span class="hljs-number">5</span>)
    at <span class="hljs-keyword">next</span> (<span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/</span>node_modules<span class="hljs-regexp">/express/</span>lib<span class="hljs-regexp">/router/</span>route.js:<span class="hljs-number">137</span>:<span class="hljs-number">13</span>)
    at Route.dispatch (<span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/</span>node_modules<span class="hljs-regexp">/express/</span>lib<span class="hljs-regexp">/router/</span>route.js:<span class="hljs-number">112</span>:<span class="hljs-number">3</span>)
    at Layer.handle [as handle_request] (<span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/</span>node_modules<span class="hljs-regexp">/express/</span>lib<span class="hljs-regexp">/router/</span>layer.js:<span class="hljs-number">95</span>:<span class="hljs-number">5</span>)
    at <span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/</span>node_modules<span class="hljs-regexp">/express/</span>lib<span class="hljs-regexp">/router/i</span>ndex.js:<span class="hljs-number">281</span>:<span class="hljs-number">22</span>
    at Function.process_params (<span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/</span>node_modules<span class="hljs-regexp">/express/</span>lib<span class="hljs-regexp">/router/i</span>ndex.js:<span class="hljs-number">335</span>:<span class="hljs-number">12</span>)
    at <span class="hljs-keyword">next</span> (<span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/</span>node_modules<span class="hljs-regexp">/express/</span>lib<span class="hljs-regexp">/router/i</span>ndex.js:<span class="hljs-number">275</span>:<span class="hljs-number">10</span>)
    at expressInit (<span class="hljs-regexp">/Users/</span>jp<span class="hljs-regexp">/example/</span>node_modules<span class="hljs-regexp">/express/</span>lib<span class="hljs-regexp">/middleware/i</span>nit.js:<span class="hljs-number">40</span>:<span class="hljs-number">5</span>)

Node.js v17.<span class="hljs-number">3.0</span></code></pre></div>
<p>And the client received an empty response.</p>
<h2 id="async-handler-to-the-rescue">Async Handler to the rescue</h2>
<p>The <a title="https://expressjs.com/en/guide/error-handling.html" href="https://expressjs.com/en/guide/error-handling.html">Express error handling documentation</a> takes pains to describe how rejected promises must be handled by calling <code>next(err)</code>. Of course, this is quite verbose and also requires the programmer to catch every single rejected promise error (in contrast to how synchronous errors are handled).</p>
<p>The documentation states that Express version 5 will fix this. <a title="https://github.com/expressjs/express/pull/2237" href="https://github.com/expressjs/express/pull/2237">Express v5 has been in development since July 2014, and does not have an expected release date</a>.</p>
<p>Fortunately, an npm package exists that fixes all this: <a title="https://www.npmjs.com/package/express-async-handler" href="https://www.npmjs.com/package/express-async-handler">express-async-handler</a>.</p>
<p>In order to use it, you need to wrap all your async requests in a function call:</p>
<div><pre class="hljs"><code>app.<span class="hljs-title function_">get</span>(
  <span class="hljs-string">"/async-example"</span>,
  <span class="hljs-title function_">asyncHandler</span>(<span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">await</span> <span class="hljs-title function_">asyncDoSomething</span>();
    res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>(<span class="hljs-string">"OK"</span>);
  })
);</code></pre></div>
<p>This is quite straightforward, but it adds unnecessary boilerplate and is quite prone to forgetting to wrap everything.</p>
<p>I would much prefer this behaviour to built into Express, and I have <a title="https://github.com/expressjs/express/issues/4535#issuecomment-843830618" href="https://github.com/expressjs/express/issues/4535#issuecomment-843830618">expressed this sentiment on GitHub</a>. Such small, fundamental, libraries should really be part of core framework in order to minimise risk of <a title="https://www.theregister.com/2016/03/23/npm_left_pad_chaos/" href="https://www.theregister.com/2016/03/23/npm_left_pad_chaos/">left-pad type incidents</a>.</p>
<p>For context, express-async-handler is <a title="https://github.com/Abazhenov/express-async-handler/blob/master/index.js" href="https://github.com/Abazhenov/express-async-handler/blob/master/index.js">8 lines of code</a> and Express has <a title="https://www.npmjs.com/package/express" href="https://www.npmjs.com/package/express">12.5 million weekly downloads</a>.</p>
<h2 id="testing-with-express-version-50">Testing with Express version 5.0</h2>
<p>In order to test the updated behaviour in Express 5.0, I updated my <code>package.json</code>:</p>
<div><pre class="hljs"><code>  <span class="hljs-attr">"dependencies"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">"express"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"git+https://github.com/expressjs/express.git#7bca2737d207189e6df65d1fee6fc735d370114e"</span>
  <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span></code></pre></div>
<p>And re-ran my test with the original unwrapped code.</p>
<div><pre class="hljs"><code>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">"/async-example"</span>, <span class="hljs-title function_">asyncHandler</span>(<span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">await</span> <span class="hljs-title function_">asyncDoSomething</span>();
  res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>(<span class="hljs-string">"OK"</span>);
}));</code></pre></div>
<div><pre class="hljs"><code>$ curl -v localhost:3000/async-example</code></pre></div>
<p>With Express v5.0 the behaviour is the same as synchronous errors in v4.x, that is:</p>
<ul>
<li>The client receives a 500 response and an HTML-formatted stack trace.</li>
<li>The node process does not exit, instead an error and stack trace are shown.</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Status of Bootstrap-Vue]]></title>
            <guid>5854e58fb7334afd88b3da51045369a9</guid>
            <pubDate>Sat, 01 Jan 2022 14:38:57 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p><a title="Bootstrap-Vue" href="Bootstrap-Vue">https://github.com/bootstrap-vue/bootstrap-vue</a> is a component library for <a title="https://vuejs.org/" href="https://vuejs.org/">Vue.js</a> that wraps and extends Bootstrap components for use in Vue.js-based web applications. It has components for <a title="https://bootstrap-vue.org/docs/components/button" href="https://bootstrap-vue.org/docs/components/button">buttons</a>, <a title="https://bootstrap-vue.org/docs/components/table" href="https://bootstrap-vue.org/docs/components/table">tables</a>, <a title="https://bootstrap-vue.org/docs/components/modal" href="https://bootstrap-vue.org/docs/components/modal">modals</a>, <a title="https://bootstrap-vue.org/docs/components/tabs" href="https://bootstrap-vue.org/docs/components/tabs">tabs</a> and loads more. The documentation is very good, and despite using it extensively I have encountered very few problems. It’s a library that I often use in my projects, and use throughout my ePOS software Little Till.</p>
<p>For a while, the maintenance status of Bootstrap-Vue has been in question. Regular contributions stopped in early 2021, with the the original author, <a title="https://github.com/pi0" href="https://github.com/pi0">Pooya Parsa</a>’s <a title="https://github.com/bootstrap-vue/bootstrap-vue/commit/f43097ea27c4362dafe96fa8b52dac4eda39e271" href="https://github.com/bootstrap-vue/bootstrap-vue/commit/f43097ea27c4362dafe96fa8b52dac4eda39e271">last contribution</a> in May 2019. Latterly <a title="https://github.com/jacobmllr95" href="https://github.com/jacobmllr95">Jacob Müller</a> made a lot of contributions, but has not been a regular presence since early 2021.</p>
<p><img src="/_resources/d736dad0119e4f7689c41046223fdb06.png" /></p>
<p><a title="https://www.npmjs.com/package/bootstrap-vue" href="https://www.npmjs.com/package/bootstrap-vue">Boostrap-Vue has roughly 200,000 weekly downloads via npm</a>.</p>
<h2 id="support-for-newer-technologies">Support for newer technologies</h2>
<p>The biggest question are around support for newer Vue and Bootstrap libraries. Bootstrap-Vue requires Vue 2 and wraps Bootstrap v4, but newer versions of Vue and Bootstrap are now available.</p>
<p>Vue 3 has been available for some time, but the Vue team are a bit unclear about its status. As of January 1 2022, <a title="https://v3.vuejs.org/guide/introduction.html" href="https://v3.vuejs.org/guide/introduction.html">the documentation says this</a>:</p>
<blockquote>
<p>All of our official libraries and tools now support Vue 3, but some of them are still in beta or release candidate status.</p>
</blockquote>
<p>Bootstrap v5 was marked as <em>stable</em> on May 5 2021.</p>
<h2 id="getting-by-in-the-dark">Getting by in the dark</h2>
<p>Throughout 2021 there was a lack of clarity regarding the future of Bootstrap-Vue. There are issues about this on GitHub (<a title="https://github.com/bootstrap-vue/bootstrap-vue/issues/5507" href="https://github.com/bootstrap-vue/bootstrap-vue/issues/5507">5507</a> <a title="https://github.com/bootstrap-vue/bootstrap-vue/issues/5196" href="https://github.com/bootstrap-vue/bootstrap-vue/issues/5196">5196</a>) without any satisfactory resolution. The most active maintainer, <a title="https://github.com/Hiws" href="https://github.com/Hiws">Hiws</a>, has been praised for providing helpful answers on GitHub and actively helping out on on the <a title="https://discord.gg/j2Mtcny" href="https://discord.gg/j2Mtcny">Bootstrap-Vue Discord</a>. However, <a title="https://github.com/bootstrap-vue/bootstrap-vue/issues/5196#issuecomment-990151947" href="https://github.com/bootstrap-vue/bootstrap-vue/issues/5196#issuecomment-990151947">Hiws has stated clearly</a> that he’s not interested in managing pull-requests or other code-based maintenance.</p>
<p>In response to discussions around Vue 3 and Bootsrap v5 support, Jacob Müller <a title="https://github.com/bootstrap-vue/bootstrap-vue/issues/6556#issuecomment-824388825" href="https://github.com/bootstrap-vue/bootstrap-vue/issues/6556#issuecomment-824388825">said in April 2021</a>:</p>
<blockquote>
<p>BootstrapVue is still maintained and will have Vue 3 and Bootstrap 5 support in the future.
There will not be ETAs in the near future but it will definitely happen.</p>
</blockquote>
<p>Sadly, that development work was never done and Hiws has had to repeatedly explain to people that the repository is unmaintained. In November, on Discord, Hiws said:</p>
<blockquote>
<p>i tried pushing the maintainers back in april/may to put out a “The project is no longer actively maintained”, so people wouldn’t be waiting around for new updates and Vue 3 support when it was likely never coming any time soon.
But i kept getting told “We will start again soon”, but soon never happened.</p>
</blockquote>
<p>Without input from either Pooya Parsa or Jacob Müller very little has happened and the conversations did not lead far. Even with a potential budget of <a title="https://opencollective.com/bootstrap-vue#category-BUDGET" href="https://opencollective.com/bootstrap-vue#category-BUDGET">roughly $20,000 raised using OpenCollective</a>, there was nobody to take the lead on the project.</p>
<h2 id="bring-on-the-forks">Bring on the forks</h2>
<p>As often happens when a beloved open source project is clearly abandoned, forks spring up.</p>
<p>Here’s a list of the forks that I am aware of.</p>
<p><a title="https://github.com/xanf" href="https://github.com/xanf">Illya Klymov</a>’s fork targeting <a title="https://v3.vuejs.org/guide/migration/migration-build.html" href="https://v3.vuejs.org/guide/migration/migration-build.html">Vue 3’s Migration Build</a>, with Bootstrap v4, created in November 2021 - discussed <a title="https://github.com/bootstrap-vue/bootstrap-vue/issues/5196#issuecomment-974596073" href="https://github.com/bootstrap-vue/bootstrap-vue/issues/5196#issuecomment-974596073">here</a>:
<a title="https://github.com/xanf/bootstrap-vue/tree/vue3-compat-build" href="https://github.com/xanf/bootstrap-vue/tree/vue3-compat-build">https://github.com/xanf/bootstrap-vue/tree/vue3-compat-build</a></p>
<p><a title="https://github.com/cdmoro" href="https://github.com/cdmoro">Carlos Bonadeo</a>’s fork targeting Vue 3, Boostrap v5 and Typescript:
<a title="https://github.com/cdmoro/bootstrap-vue-3" href="https://github.com/cdmoro/bootstrap-vue-3">https://github.com/cdmoro/bootstrap-vue-3</a></p>
<p>Carlos’s fork appears to be a complete rewrite that attempts to match the Bootstrap-Vue API. <a title="https://cdmoro.github.io/bootstrap-vue-3/getting-started/#why-bootstrapvue3" href="https://cdmoro.github.io/bootstrap-vue-3/getting-started/#why-bootstrapvue3">It’s documentation states</a> <em>NOT PRODUCTION READY</em> and critically it appears to be missing a <a title="https://cdmoro.github.io/bootstrap-vue-3/components/" href="https://cdmoro.github.io/bootstrap-vue-3/components/">table component</a>.</p>
<p>Also of note is a <a title="https://github.com/bootstrap-vue/bootstrap-vue/issues/6872#issuecomment-999822688" href="https://github.com/bootstrap-vue/bootstrap-vue/issues/6872#issuecomment-999822688">recently released</a> library targeting Bootstrap v5 and Vue 3, but which does not appear to attempt any API compatibility with the original Bootstrap-Vue project:  <a title="https://coreui.io/bootstrap-vue/" href="https://coreui.io/bootstrap-vue/">https://coreui.io/bootstrap-vue/</a>.</p>
<p>In my view, given that there is no attempt to maintain API compatibility with Bootstrap-Vue, it is confusing that CoreUI have decided use this name, even if it’s the most obvious choice for a project combining Bootstrap and Vue.</p>
<h2 id="a-new-era-dawns">A new era dawns</h2>
<p>Things took a more positive turn on 14 December 2021 when Pooya resurfaced with <a title="https://github.com/bootstrap-vue/bootstrap-vue/issues/5196#issuecomment-993881245" href="https://github.com/bootstrap-vue/bootstrap-vue/issues/5196#issuecomment-993881245">this comment</a>:</p>
<blockquote>
<p>Thanks for starting to work on vue3 support @xanf @cdmoro 💚 If you would like to dedicate more time, I can invite you to org, and also we have funds available in open-collective.</p>
</blockquote>
<p>Subsequently Carlos Bonadeo (cdmoro) and Illya Klymov (xanf) were made maintainers of the Bootstrap-Vue repository. Since then Illya has got on with some basic tidy up and merging of simple pull requests.</p>
<p>The latest update is contained in this pinned issue:
<a title="https://github.com/bootstrap-vue/bootstrap-vue/issues/6872" href="https://github.com/bootstrap-vue/bootstrap-vue/issues/6872">https://github.com/bootstrap-vue/bootstrap-vue/issues/6872</a></p>
<blockquote>
<p>TL; DR</p>
<p>New maintainers are here</p>
<p>Pull requests will be reviewed within several days</p>
<p>There will be a new release of bootstrap-vue coming with fixes included</p>
<p>Primary goal of the team is to rewrite bootstrap-vue to support Vue 3 and Bootstrap v5. We will do this in a separate repository. We will announce the detailed roadmap for a rewrite as soon as we have it</p>
</blockquote>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iPhone keeps connecting and disconnecting]]></title>
            <guid>7d97e63587204b4e844183edfb1c3e70</guid>
            <pubDate>Thu, 30 Dec 2021 13:34:47 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>I occasionally do iOS application development, and in some cases want to test the application on my phone.</p>
<p>I have an iPhone XS and a 2015 Macbook Pro.</p>
<p>I am afflicted by the issue described here:
<a title="https://www.ifixit.com/Answers/View/473839/iOS+devices+connecting+and+disconnecting+rapidly" href="https://www.ifixit.com/Answers/View/473839/iOS+devices+connecting+and+disconnecting+rapidly">https://www.ifixit.com/Answers/View/473839/iOS+devices+connecting+and+disconnecting+rapidly</a>.</p>
<p>That is, when I connect my iPhone to my laptop via USB the computer shows the iPhone connecting and disconnecting rapidly. This makes it impossible to use as a test device.</p>
<p>I have tried, without success:</p>
<ul>
<li>Using different cables, including genuine Apple ones.</li>
<li>Using both USB ports on the laptop.</li>
</ul>
<p>What works reliably is using a powered USB hub. But carrying one of those around is inconvenient, and I don’t have one with me now.</p>
<p>The solutions listed in the thread include:</p>
<ul>
<li>Trying a different cable.</li>
<li>Force quitting the usbd process.</li>
<li>Performing an <em>SMC reset</em>.</li>
<li>Charging phone to 100%.</li>
</ul>
<p>I recall that force quitting usbd has worked for me in the past, but does not seem to work now. Force quitting usbd via activity monitor causes my phone to disappear from the Device Setup screen, and replugging causes the repeated disconnected behaviour to resume.</p>
<h2 id="a-solution">A solution</h2>
<p>I ran the following in the terminal:</p>
<div><pre class="hljs"><code>sudo killall -<span class="hljs-literal">STOP</span> -c usbd</code></pre></div>
<p>And noticed that although the Device Setup screen didn’t list my phone, the Next button was still enabled. Clicking Next allowed me to build and run my app on my phone.</p>
<p>Running this command from the command line should do the same thing as force quit in activity monitor. More testing is required to see whether using force quit in activity monitor allows this behaviour.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Improving Joplin's Image Rendering]]></title>
            <guid>731199ec4f974459a09dbb8f77e91c5b</guid>
            <pubDate>Wed, 29 Dec 2021 12:42:42 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>When pasting screenshots from Mac OS, they are shown at 2x resolution in Joplin (and in rendered GitHub pages) since that’s how Mac OS captures them on a retina screen.</p>
<p>If you take a screenshot on Mac OS and open Preview, then create a new document with the contents of the clipboard, the resulting .png file will be twice the width and twice the height of the original screenshot.</p>
<p>Critically though, when pasting into Preview, Mac OS recognises that the Image DPI is 144 pixels/inch (instead of the regular 72 pixels/inch).</p>
<p>Here’s a 70 x 70 screenshot I took:</p>
<p><img src="/_resources/2901de9d1c474df9a2dbf74ffda376ce.png" /></p>
<p>Pasting into Preview the Info panel shows a 140 x 140 pixel image, but recognizes the image DPI.</p>
<p><img src="/_resources/bbf792f39ac54abba132b484b22042b7.png" /></p>
<p>Opening the image after it has been pasted into Joplin (by right clicking on the image and selecting <em>Reveal file in Finder)</em> shows that the image DPI information has been lost.</p>
<p><img src="/_resources/b4fcd6e3c161420a826af0b6115a30c6.png" /></p>
<h2 id="tl-dr">TL ; DR</h2>
<p>It seems like <a title="https://github.com/electron/electron" href="https://github.com/electron/electron">Electron</a>, on which Joplin is based, does not preserve image EXIF data when reading from the Clipboard.</p>
<p>There is some ongoing work to improve Electron’s clipboard API which may address this issue:
<a title="https://github.com/electron/governance/pull/454" href="https://github.com/electron/governance/pull/454">https://github.com/electron/governance/pull/454</a></p>
<p>The above pull request references the following issue, created in April 2020 by fabiospampinato (author of <a title="https://github.com/notable/notable" href="https://github.com/notable/notable">Notable</a>) that requests better support for reading images from the clipboard.
<a title="https://github.com/electron/electron/issues/23156" href="https://github.com/electron/electron/issues/23156">https://github.com/electron/electron/issues/23156</a></p>
<h2 id="potential-solutions">Potential Solutions</h2>
<p>Some thoughts on how to address this issue.</p>
<h3 id="find-a-screenshot-app-that-rescales-screenshots">Find a screenshot app that rescales screenshots</h3>
<p>It’s likely that an app exists on Mac OS that will take and rescale screenshots automatically.</p>
<h3 id="see-whether-joplin-can-identify-high-dpi-screenshots">See whether Joplin can identify high-DPI screenshots</h3>
<p>Perhaps Joplin could intercept the <em>paste</em> command and rescale the image before saving its copy?</p>
<h3 id="see-whether-exif-data-would-allow-the-joplin-renderer-to-add-width-and-height-attributes">See whether EXIF data would allow the Joplin renderer to add width and height attributes</h3>
<p>Perhaps there is something in the EXIF data of the png file that would allow Jopiln’s <code>img</code> renderer to identify that width and height attributes should be added at half the images natural resolution?</p>
<h2 id="to-figure-out">To figure out</h2>
<h3 id="is-there-anything-in-the-exif-or-other-data-from-a-screenshot-that-tells-you-it-has-been-taken-at-double-dpi">Is there anything in the EXIF (or other) data from a screenshot that tells you it has been taken at double-DPI?</h3>
<p>Summary: YES, a DPI of 144 is stored in the image’s EXIF data.</p>
<p>After taking a screenshot, saving as a PNG, it simply shows up as having double sized dimensions in the Mac OS file info screen.</p>
<p>Using the <code>file</code> utility doesn’t show the DPI:</p>
<div><pre class="hljs"><code><span class="hljs-attribute">file</span> screenshot-<span class="hljs-number">1</span>.png
<span class="hljs-attribute">screenshot</span>-<span class="hljs-number">1</span>.png: PNG image data, <span class="hljs-number">232</span> x <span class="hljs-number">250</span>, <span class="hljs-number">8</span>-bit/color RGBA, non-interlaced</code></pre></div>
<p>But in the general tab of Preview, you can see the DPI is 144:
<img src="/_resources/58a2b2358c4b4ffeaf80450dd58d6abc.png" /></p>
<p>ImageMagick’s <code>identify</code> tool shows that the DPI is stored in the image’s EXIF data:</p>
<div><pre class="hljs"><code><span class="hljs-attribute">identify</span> -format '%[EXIF:*]' screenshot-<span class="hljs-number">1</span>.png
<span class="hljs-attribute">exif</span>:ExifOffset=<span class="hljs-number">90</span>
<span class="hljs-attribute">exif</span>:Orientation=<span class="hljs-number">1</span>
<span class="hljs-attribute">exif</span>:PixelXDimension=<span class="hljs-number">232</span>
<span class="hljs-attribute">exif</span>:PixelYDimension=<span class="hljs-number">250</span>
<span class="hljs-attribute">exif</span>:ResolutionUnit=<span class="hljs-number">2</span>
<span class="hljs-attribute">exif</span>:UserComment=<span class="hljs-number">65</span>, <span class="hljs-number">83</span>, <span class="hljs-number">67</span>, <span class="hljs-number">73</span>, <span class="hljs-number">73</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">83</span>, <span class="hljs-number">99</span>, <span class="hljs-number">114</span>, <span class="hljs-number">101</span>, <span class="hljs-number">101</span>, <span class="hljs-number">110</span>, <span class="hljs-number">115</span>, <span class="hljs-number">104</span>, <span class="hljs-number">111</span>, <span class="hljs-number">116</span>
<span class="hljs-attribute">exif</span>:XResolution=<span class="hljs-number">144</span>/<span class="hljs-number">1</span>
<span class="hljs-attribute">exif</span>:YResolution=<span class="hljs-number">144</span>/<span class="hljs-number">1</span></code></pre></div>
<p>But importantly, after pasting into Joplin, the EXIF data is lost:</p>
<div><pre class="hljs"><code>identify -<span class="hljs-built_in">format</span> <span class="hljs-string">'%[EXIF:*]'</span> c41d8c9e49774020a93ac6956112b0b6.png</code></pre></div>
<p>So even if the web browser could identify the DPI (can it?), it won’t be able to since it’s not preserved.</p>
<h3 id="what-does-the-mac-os-clipboard-api-look-like-when-the-clipboard-stores-a-screenshot-does-it-show-pixel-density">What does the Mac OS clipboard API look like? When the clipboard stores a screenshot, does it show pixel density?</h3>
<h2 id="research">Research</h2>
<p>How can I stop my retina display from taking 2x sized screenshots?
<a title="https://apple.stackexchange.com/questions/105185/how-can-i-stop-my-retina-display-from-taking-2x-sized-screenshots" href="https://apple.stackexchange.com/questions/105185/how-can-i-stop-my-retina-display-from-taking-2x-sized-screenshots">https://apple.stackexchange.com/questions/105185/how-can-i-stop-my-retina-display-from-taking-2x-sized-screenshots</a></p>
<p>EXIF
<a title="https://en.wikipedia.org/wiki/Exif" href="https://en.wikipedia.org/wiki/Exif">https://en.wikipedia.org/wiki/Exif</a></p>
<p>How do I take a MacOS Retina screenshot and get the image at its actual size?
<a title="https://o7planning.org/12711/how-do-i-take-a-macos-retina-screenshot-and-get-the-image-at-its-actual-size" href="https://o7planning.org/12711/how-do-i-take-a-macos-retina-screenshot-and-get-the-image-at-its-actual-size">https://o7planning.org/12711/how-do-i-take-a-macos-retina-screenshot-and-get-the-image-at-its-actual-size</a></p>
<ul>
<li>A tutorial showing how to use Automator to save resized versions of screenshots.</li>
</ul>
<p>Searching for EXIF on Joplin’s Subreddit, no results:
<a title="https://www.reddit.com/r/joplinapp/search/?q=exif&amp;restrict_sr=1&amp;sr_nsfw=" href="https://www.reddit.com/r/joplinapp/search/?q=exif&amp;restrict_sr=1&amp;sr_nsfw=">https://www.reddit.com/r/joplinapp/search/?q=exif&amp;restrict_sr=1&amp;sr_nsfw=</a></p>
<p>Searching for EXIT on Joplin’s support forum:
<a title="https://discourse.joplinapp.org/search?q=exif" href="https://discourse.joplinapp.org/search?q=exif">https://discourse.joplinapp.org/search?q=exif</a></p>
<p>This application, Maccy, remembers clipboard history on Mac OS. Perhaps we can look at the source code to see what the Mac OS clipboard API looks like?
<a title="https://github.com/p0deje/Maccy" href="https://github.com/p0deje/Maccy">https://github.com/p0deje/Maccy</a></p>
<h2 id="similar-joplin-github-issues">Similar Joplin GitHub issues</h2>
<p>Images sometimes improperly rotated #3383
<a title="https://github.com/laurent22/joplin/issues/3383" href="https://github.com/laurent22/joplin/issues/3383">https://github.com/laurent22/joplin/issues/3383</a></p>
<ul>
<li>This issue also related to EXIF data.</li>
</ul>
<p>Keep original image rather than compressing, please #1232
<a title="https://github.com/laurent22/joplin/issues/1232" href="https://github.com/laurent22/joplin/issues/1232">https://github.com/laurent22/joplin/issues/1232</a></p>
<ul>
<li>This issue also has a discussion of EXIF data.</li>
<li>It points to the following part of the code which may be relevant: ./ReactNativeClient/lib/shim-init-node.js:141-148:</li>
</ul>
<h2 id="examining-joplin-source-code">Examining Joplin source code</h2>
<p>Building the Mac OS Desktop client by following <a title="https://github.com/laurent22/joplin/blob/dev/BUILD.md" href="https://github.com/laurent22/joplin/blob/dev/BUILD.md">https://github.com/laurent22/joplin/blob/dev/BUILD.md</a>.</p>
<p>After taking a little while on <code>yarn install</code> and finishing first time with errors and second time with warnings, loading the desktop app works:</p>
<p><img src="/_resources/32cad17d62424a218366ccc47026baac.png" /></p>
<h3 id="electrons-nativeimage-class">Electron’s NativeImage Class</h3>
<p>Some of the code to handle image resizing is here:</p>
<p>packages/lib/shim-init-node.js line 162</p>
<div><pre class="hljs"><code><span class="hljs-keyword">let</span> image = nativeImage.create<span class="hljs-constructor">FromPath(<span class="hljs-params">filePath</span>)</span>;</code></pre></div>
<p>It uses Electronic’s NativeImage class:
<a title="https://www.electronjs.org/docs/latest/api/native-image/#imageisempty" href="https://www.electronjs.org/docs/latest/api/native-image/#imageisempty">https://www.electronjs.org/docs/latest/api/native-image/#imageisempty</a></p>
<p>Clipboard data is retrieved using Electron’s clipboard.readImage:
<a title="https://www.electronjs.org/docs/latest/api/clipboard/#clipboardreadimagetype" href="https://www.electronjs.org/docs/latest/api/clipboard/#clipboardreadimagetype">https://www.electronjs.org/docs/latest/api/clipboard/#clipboardreadimagetype</a></p>
<h2 id="electron-issues">Electron Issues</h2>
<p>OPEN:  Clipboard: improved support for reading images #23156
<a title="https://github.com/electron/electron/issues/23156" href="https://github.com/electron/electron/issues/23156">https://github.com/electron/electron/issues/23156</a></p>
<ul>
<li>The issue author is writing a note taking app.</li>
<li>The issue is around preserving original clipboard data.</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Joplin to publish GitHub Pages]]></title>
            <guid>727e7afd306f4ab5be8ba3f4baf1fbed</guid>
            <pubDate>Tue, 28 Dec 2021 14:25:55 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>I discovered that Joplin includes a plugin for publishing to GitHub pages. I wanted to check it out to see how well it works.</p>
<h2 id="installation">Installation</h2>
<p>Open Preferences and search for <em>Pages Publisher</em>. Install the Pages Publisher plugin:</p>
<p><img src="/_resources/febb2178432549208a08bed839a98d43.png" /></p>
<p>After restarting Joplin, a new Pages Publisher option is availble in the preferences.</p>
<p><img src="/_resources/0ac7e0aef08049adac15af00e956f49b.png" /></p>
<p>It requires a GitHub access token with the public_repo scope.</p>
<p>In <a title="https://github.com/settings/tokens/new" href="https://github.com/settings/tokens/new">https://github.com/settings/tokens/new</a> I created a new token with just that permission.</p>
<p><img src="/_resources/be4922a4fe0e4b02a7aa9a43fae4ca8e.png" /></p>
<p>I added the GitHub token in the Joplin preferences.</p>
<p>In the Tools menu, there is an option to Open Pages Publisher:</p>
<p><img src="/_resources/dec53b185b4e472787a8fc2513ff0ab8.png" /></p>
<p>When you open it, a new panel appears:</p>
<p><img src="/_resources/830bd719d9ab472688afd40560abb924.png" /></p>
<h2 id="usage">Usage</h2>
<p>The user guide is here: <a title="https://github.com/ylc395/joplin-plugin-pages-publisher/wiki/User-Guide" href="https://github.com/ylc395/joplin-plugin-pages-publisher/wiki/User-Guide">https://github.com/ylc395/joplin-plugin-pages-publisher/wiki/User-Guide</a></p>
<p>I already have a blog on GitHub pages, under “blog”:
<a title="https://euoia.github.io/blog/making-bread/" href="https://euoia.github.io/blog/making-bread/">https://euoia.github.io/blog/making-bread/</a></p>
<p>This is covered the FAQ, no special action is required.</p>
<p>When I go to add Articles, it shows “No Data”:</p>
<p><img src="/_resources/5df3c55d4dd34a88b0d5246955643f2f.png" /></p>
<p>Perhaps it’s because I didn’t configure my GitHub settings yet?</p>
<p>Indeed, after configuring my GitHub settings and Quitting and reopening the plugin, my notes are showing up. I was able to add this note:</p>
<p><img src="/_resources/86d50163b3ce4d7e8f9d28fcc5e09de8.png" /></p>
<p>Then click Generate to publish the site:</p>
<p><img src="/_resources/0c3e2beabb9745c08d18685b33e41b92.png" /></p>
<p>My site is now available at <a title="https://euoia.github.io" href="https://euoia.github.io">https://euoia.github.io</a>:</p>
<p><img src="/_resources/4dd7990b71114114ba866b6410b1f7c4.png" /></p>
<p>But where is my article?</p>
<p>It shows in the Archives:
<a title="https://euoia.github.io/archives" href="https://euoia.github.io/archives">https://euoia.github.io/archives</a></p>
<p>Is it supposed to show on the main page?</p>
<p>This is something I may wish to address later.</p>
<h2 id="updating-articles">Updating Articles</h2>
<p>I noticed that when I changed my note, the published version didn’t change.</p>
<p>Indeed, if you reload the Articles tab, it shows you that the note has changed and you have to manually Sync the updated content.</p>
<p><img src="/_resources/274dd45f91ef46ab9c02e20be007b8e7.png" /></p>
<p>I wonder if that’s something that can be done automatically?</p>
<h2 id="creating-a-custom-theme">Creating a custom theme</h2>
<p>I wanted to be able to tweak a few things in my theme. I also wanted to see what the process looks like, because it’s quite likely I will want to change a few things later on and it would be nice to know what’s involved.</p>
<p>The documentation is really clear and works well:
<a title="https://github.com/ylc395/joplin-plugin-pages-publisher/wiki/How-to-create-a-custom-theme" href="https://github.com/ylc395/joplin-plugin-pages-publisher/wiki/How-to-create-a-custom-theme">https://github.com/ylc395/joplin-plugin-pages-publisher/wiki/How-to-create-a-custom-theme</a></p>
<p>So I created a custom theme, which I’ve pushed to GitHub here:
<a title="https://github.com/euoia/joplin-pages-pickle-theme" href="https://github.com/euoia/joplin-pages-pickle-theme">https://github.com/euoia/joplin-pages-pickle-theme</a></p>
<p>At the moment, it just changes the appearance of the article timestamps, which I thought were a bit too in-your-face. Here’s my updated version:</p>
<p><img src="/_resources/c41d8c9e49774020a93ac6956112b0b6.png" /></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Bread recipe using poolish]]></title>
            <guid>fff5faacf09d49ed8de3af90f00713ef</guid>
            <pubDate>Tue, 24 Mar 2020 14:49:00 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>This is my standard bread recipe, which as of December 2021 is pretty much the only bread recipe I use. It’s fairly tolerant to variations in the weights and timings, and is the basis for my cheese bread recipe.</p>
<p>The recipe starts by making a <em>poolish</em>, which is a kind of batter, and leaving it for at least 12 hours before mixing it with a denser mixture for the final loaf.</p>
<p>This recipe makes two loaves of roughly 875 grams wet mixture each.</p>
<h2 id="making-the-poolish">Making the Poolish</h2>
<p>A poolish should be made at least 12 hours before starting the loaf proper. Typically I do this the in the evening, then make the bread the following morning.</p>
<p>Combine loosely in a large bowl:</p>
<ul>
<li>500 grams Strong White Bread Flour</li>
<li>500 grams 30 °C Water</li>
<li>¼ teaspoon Allison’s dried instant easy bake yeast</li>
</ul>
<p>Cover with clingfilm or a damp tea towel and leave at room temperature for 12 to 20 hours.</p>
<h2 id="making-the-loaf">Making the loaf</h2>
<p>After resting the poolish for at least 12 hours it should be sticky and bubbly.</p>
<p>You will need:</p>
<ul>
<li>500 grams Strong White Bread Flour</li>
<li>21 grams kosher salt</li>
<li>¾ tsp Allison’s dried instant easy bake yeast</li>
<li>250 grams 40 °C water</li>
<li>All of the poolish</li>
</ul>
<ol>
<li>In a large bowl combine the dry ingredients: flour, salt, yeast.</li>
<li>Add the water to the poolish to loosen it from the sides of the bowl and scrape it into the other bowl.</li>
<li>Keeping a bowl of water nearby to wet your hands, mix the ingredients with your hands by folding and pinching alternately for about 3 minutes, until the ingredients are integrated and there is not much dry flour. The dough will be very shaggy.</li>
<li>Wait 30 minutes then stretch and fold.</li>
<li>Wait another 30 minutes then stretch and fold.</li>
<li>Wait another 30 minutes then stretch and fold.</li>
<li>Leave the dough covered with a damp tea towel for a further hour.</li>
<li>Put dough on floured surface and cut in half. Shape each half into boules and place one boule seam side down into a floured banneton or floured towel lined bowl. Wrap the other half of the dough in clingfilm and keep in a bowl in the fridge for a day or two. When you’re ready, you can remove it before transferring to a banneton and proceeding with the next step.</li>
<li>Set oven to 220 °C Fan (240 °C conventional oven). Place a cast-iron dutch oven in the oven with its lid on.</li>
<li>Wait an hour for the dutch oven to heat up and for the dough to rise.</li>
<li>Tear a piece of greaseproof paper large enough to accommodate the dough, with extra at the sides for lifting.</li>
<li>After an hour, flip the banneton upside down onto greaseproof paper. Carefully remove the banneton, trying not to tear the dough too much. Lift the dough by picking up the edges of the greeseproof and transfer into the dutch oven.</li>
<li>Bake for 30 to 35 minutes with the lid on, then 15 to 20 minutes with the lid off.</li>
</ol>
<h2 id="cheese-bread">Cheese Bread</h2>
<p>To make a cheesy variant of this recipe, chop 250 grams of emmental (the older and smellier the better) into 1.5 centimetre cubed pieces and fold into the centre of the dough as you make a boule. It will seem like a lot of cheese, but I have found it works really well.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Neovim Dot App]]></title>
            <guid>c4c30ec154c449a4946d822616852a06</guid>
            <pubDate>Wed, 13 Nov 2019 06:42:13 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="creating-a-standalone-executable-for-neovim-based-on-iterm2">Creating a standalone executable for Neovim based on iTerm2</h2>
<p><img src="./cover-image.png" alt="Neovim running as a standalone app" /></p>
<p>I use Neovim on OS X as my code editor.</p>
<p>I am quite happy to use it in the terminal, but I find it helpful to have a
separate application that I can run in full screen and can switch to
independently of iTerm2.</p>
<p>I tried some of the standalone Neovim applications, but was generally unhappy
with them for one reason or another. So I decided to make a standalone version
that runs inside iTerm2.</p>
<p>Running Neovim this way is great because it leverages the power and stability
of iTerm2. iTerm2 has great support for customization of appearance and
keyboard rebinding.</p>
<p>Here’s how to build a standalone version of Neovim that’s based on iTerm2.</p>
<p>I am not a developer of Mac applications, so the following is based on a bit of
trial and error and fiddling around with XCode. This is the method I’ve used to
build a standalone version of Neovim several times across several versions of
Neovim and XCode.</p>
<p>These steps have been tested with XCode 11.2.</p>
<ol>
<li>
<p>Clone iTerm2 master from GitHub <a title="https://github.com/gnachman/iTerm2" href="https://github.com/gnachman/iTerm2">https://github.com/gnachman/iTerm2</a></p>
</li>
<li>
<p>Open XCode and choose “Open another project…”. Select the directory where you cloned iTerm2.</p>
</li>
</ol>
<p><img src="/_resources/8ef9f72d90b34027ad852a630fc0c096.png" /></p>
<ol start="3">
<li>Change Bundle ID to (something like) co.uk.cloudship.neovim</li>
</ol>
<p><img src="/_resources/a64cc201eeb24700b46c067a735fdfaf.png" /></p>
<ol start="4">
<li>Under Signing &amp; Capabilities change to “Sign to run locally”</li>
</ol>
<p><img src="/_resources/75c89d478b9d4e1584c3ca6fa96e2529.png" /></p>
<ol start="5">
<li>In the right-hand pane change Name to Neovim</li>
</ol>
<p><img src="/_resources/acf4ff97770d472f9f8195ca85f322d4.png" /></p>
<p>A window will appear helping you rename all instances of iTerm2 to Neovim.</p>
<ol start="6">
<li>Update the icons.</li>
</ol>
<p>Find Supporting Files &gt; Images &gt; Media.xcassets (you can use the filter at the
bottom of the file list window)</p>
<p>Grab the Neovim icon from here:
<a title="https://raw.githubusercontent.com/neovim/neovim.github.io/master/logos/neovim-mark.png" href="https://raw.githubusercontent.com/neovim/neovim.github.io/master/logos/neovim-mark.png">https://raw.githubusercontent.com/neovim/neovim.github.io/master/logos/neovim-mark.png</a></p>
<p>I used Iconfly to generate AppIcon.appiconset (select generate without scaling).</p>
<p>Drag the AppIcon.appiconset folder to Xterm.</p>
<p>Remove the old icon set and rename the new one to the old name.</p>
<p><img src="/_resources/f37903666cca45edbb2e8266d788fe17.png" /></p>
<ol start="7">
<li>I tried building at this point but it failed due to a reference somewhere to iTerm2.pch.</li>
</ol>
<p>In XCode, select the project and go to Build Settings.</p>
<p>Under targets select NeovimSharedArc.</p>
<p>In the filter, enter GCC_PREFIX.</p>
<p>Under the setting Prefix Header, update the value to <code>sources/Neovim.pch</code>.</p>
<p><img src="/_resources/a7e3408ec40e43fd8391dcab772363dd.png" /></p>
<ol start="8">
<li>
<p>Replace all references to <code>iTerm2SharedARC-Swift.h</code> with <code>NeovimSharedARC-Swift.h</code></p>
</li>
<li>
<p>Build the application by hitting ⌘-R.</p>
</li>
<li>
<p>Copy Neovim to applications.</p>
</li>
</ol>
<p>Under Products right click on Neovim.app and select “Show in Finder”.</p>
<p>Move Neovim.app to applications.</p>
<ol start="10">
<li>All done!</li>
</ol>
<p>You should be able to run Neovim.app now.</p>
<p>What I did after this was create a separate profile for Neovim in iTerm2 that
runs the following at startup: <code>nvim &amp;&amp; exit</code>. This option is under Profiles &gt;
General as “send text at start”) in the iTerm2 (and now Neovim) preferences.</p>
<p><img src="/_resources/35d20621abd245eca429574ed6478943.png" /></p>
]]></content:encoded>
        </item>
    </channel>
</rss>