<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Will Jessop&#39;s Writings</title>
    <link>https://willj.net/</link>
    <description>Recent content on Will Jessop&#39;s Writings</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <managingEditor>will@willj.net (Will Jessop)</managingEditor>
    <webMaster>will@willj.net (Will Jessop)</webMaster>
    <copyright>&amp;#169; Will Jessop. All rights reserved.</copyright>
    <lastBuildDate>Tue, 23 Jun 2020 18:03:31 +0100</lastBuildDate>
    <atom:link href="https://willj.net/" rel="self" type="application/rss+xml" />
      
      
      <item>
      <title>Fixing errors installing the charlock_holmes ruby gem redux</title>
      <link>https://willj.net/posts/fixing-errors-installing-the-charlock_holmes-ruby-gem-redux/</link>
      <pubDate>Thu, 29 May 2025 10:50:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/fixing-errors-installing-the-charlock_holmes-ruby-gem-redux/</guid>
      <description>&lt;p&gt;A while back I posted about &lt;a href=&#34;https://willj.net/posts/fixing-errors-installing-the-charlock_holmes-ruby-gem/&#34;&gt;fixing an error installing the charlock_holmes gem on MacOS&lt;/a&gt;, well the error has returned. Here&amp;rsquo;s the newest fix.&lt;/p&gt;
&lt;p&gt;If you get an error that looks something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current directory:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/charlock_holmes-0.7.9/ext/charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/bin/ruby extconf.rb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-opt-dir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;/usr/local/opt --with-opt-include&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;/usr/local/opt/icu4c/include
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-opt-lib&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;/usr/local/opt/icu4c/lib --with-cxxflags&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;-std&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;c++11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; pkg-config &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu-i18n...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I/opt/homebrew/Cellar/icu4c@77/77.1/include &amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-L/opt/homebrew/Cellar/icu4c@77/77.1/lib&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-licui18n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; pkg-config &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu-io...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I/opt/homebrew/Cellar/icu4c@77/77.1/include &amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-L/opt/homebrew/Cellar/icu4c@77/77.1/lib&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-licuio&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; pkg-config &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu-uc...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I/opt/homebrew/Cellar/icu4c@77/77.1/include &amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-L/opt/homebrew/Cellar/icu4c@77/77.1/lib&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-licuuc&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -licui18n... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; unicode/ucnv.h... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -lz... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -licuuc... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -licudata... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu that requires explicit C++ version flag... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu that compiles with c++20 standard... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Static linking is disabled.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;creating Makefile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current directory:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/charlock_holmes-0.7.9/ext/charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make DESTDIR&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt; sitearchdir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;./.gem.20250529-47905-r2zqyx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sitelibdir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;./.gem.20250529-47905-r2zqyx clean
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current directory:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/charlock_holmes-0.7.9/ext/charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make DESTDIR&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt; sitearchdir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;./.gem.20250529-47905-r2zqyx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sitelibdir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;./.gem.20250529-47905-r2zqyx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling converter.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from converter.c:2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ./common.h:9:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby.h:38:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/ruby.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/internal/anyargs.h:83:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:6:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MAJOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MINOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                     ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; warnings generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling encoding_detector.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from encoding_detector.c:2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ./common.h:9:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby.h:38:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/ruby.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/internal/anyargs.h:83:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:6:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MAJOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MINOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                     ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; warnings generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling ext.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ext.c:1:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ./common.h:9:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby.h:38:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/ruby.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/internal/anyargs.h:83:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:6:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MAJOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MINOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                     ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; warnings generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling transliterator.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:15:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/utypes.h:39:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/uversion.h:182:11: warning:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nested namespace definition is a C++17 extension; define each namespace
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;separately &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wc++17-extensions&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;182&lt;/span&gt; | namespace U_HEADER_ONLY_NAMESPACE &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |           ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/uversion.h:180:48: note:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;expanded from macro &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;U_HEADER_ONLY_NAMESPACE&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;180&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#define U_HEADER_ONLY_NAMESPACE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;U_ICU_NAMESPACE::U_HEADER_NESTED_NAMESPACE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:271:38: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;271&lt;/span&gt; | template&amp;lt;typename T, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;std::is_same_v&amp;lt;T,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;UChar&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                 ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:271:55: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same_v&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;; did you mean &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;271&lt;/span&gt; | template&amp;lt;typename T, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;std::is_same_v&amp;lt;T,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;UChar&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                  ~~~~~^~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                       is_same
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_same.h:22:29:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;note: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt; declared here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; | struct _LIBCPP_TEMPLATE_VIS is_same : _BoolConstant&amp;lt;__is_same&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;_Tp, _Up&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:273:8: warning:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;constexpr &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; is a C++17 extension &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wc++17-extensions&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;273&lt;/span&gt; |     &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; constexpr &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;std::is_same_v&amp;lt;UChar, char16_t&amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |        ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:273:24: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same_v&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;; did you mean &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;273&lt;/span&gt; |     &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; constexpr &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;std::is_same_v&amp;lt;UChar, char16_t&amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                   ~~~~~^~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                        is_same
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_same.h:22:29:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;note: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt; declared here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; | struct _LIBCPP_TEMPLATE_VIS is_same : _BoolConstant&amp;lt;__is_same&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;_Tp, _Up&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:273:50: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;expected unqualified-id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;273&lt;/span&gt; |     &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; constexpr &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;std::is_same_v&amp;lt;UChar, char16_t&amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                  ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:385:16: warning:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;variable templates are a C++14 extension &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wc++14-extensions&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;385&lt;/span&gt; | constexpr bool ConvertibleToU16StringView &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:386:10: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_convertible_v&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;; did you mean
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_convertible&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;386&lt;/span&gt; |     std::is_convertible_v&amp;lt;T, std::u16string_view&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |     ~~~~~^~~~~~~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |          is_convertible
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_convertible.h:22:29:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;note: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_convertible&amp;#39;&lt;/span&gt; declared here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; | struct _LIBCPP_TEMPLATE_VIS is_convertible : public
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;integral_constant&amp;lt;bool, __is_convertible&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;_T1, _T2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:393:5: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;expected &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;(&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;-style cast or type construction
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;386&lt;/span&gt; |     std::is_convertible_v&amp;lt;T, std::u16string_view&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;387&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if !U_CHAR16_IS_TYPEDEF &amp;amp;&amp;amp; (!defined(_LIBCPP_VERSION) ||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_LIBCPP_VERSION &amp;lt; 180000&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;388&lt;/span&gt; |     &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; std::is_convertible_v&amp;lt;T, std::basic_string_view&amp;lt;uint16_t&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;389&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;390&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if U_SIZEOF_WCHAR_T==2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;391&lt;/span&gt; |     &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; std::is_convertible_v&amp;lt;T, std::wstring_view&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;392&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;393&lt;/span&gt; |     ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |     ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:429:36: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;type named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;429&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;!std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                      ~~~~~~~~~~~~~~^~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:429:47: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;expected &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt; or &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;gt;&amp;#39;&lt;/span&gt; in template-parameter-list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;429&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;!std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                               ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:429:93: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;expected unqualified-id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;429&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;!std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:439:36: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;type named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;439&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                      ~~~~~~~~~~~~~~^~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:439:47: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;expected &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt; or &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;gt;&amp;#39;&lt;/span&gt; in template-parameter-list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;439&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                               ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:439:92: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;expected unqualified-id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;439&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:40:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/stringpiece.h:134:29: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;134&lt;/span&gt; |             typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                        ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/stringpiece.h:135:23: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same_v&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;; did you mean &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;135&lt;/span&gt; |                 &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;std::is_same_v&amp;lt;decltype&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;.data&lt;span style=&#34;color:#f92672&#34;&gt;())&lt;/span&gt;, const char*&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                  ~~~~~^~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                       is_same
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_same.h:22:29:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;note: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt; declared here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; | struct _LIBCPP_TEMPLATE_VIS is_same : _BoolConstant&amp;lt;__is_same&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;_Tp, _Up&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:40:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/stringpiece.h:140:17: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;use of address-of-label extension outside of a &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; body
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;140&lt;/span&gt; |                 std::is_same_v&amp;lt;decltype&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;.size&lt;span style=&#34;color:#f92672&#34;&gt;())&lt;/span&gt;, size_t&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                 ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/stringpiece.h:140:62: error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;expected member name or &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt; after declaration specifiers
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;140&lt;/span&gt; |                 std::is_same_v&amp;lt;decltype&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;.size&lt;span style=&#34;color:#f92672&#34;&gt;())&lt;/span&gt;, size_t&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                              ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:346:40: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;346&lt;/span&gt; |   template&amp;lt;typename S, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;ConvertibleToU16StringView&amp;lt;S&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                   ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:381:40: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;381&lt;/span&gt; |   template&amp;lt;typename S, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;ConvertibleToU16StringView&amp;lt;S&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                   ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:1959:40: error: no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1959&lt;/span&gt; |   template&amp;lt;typename S, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std::enable_if_t&amp;lt;ConvertibleToU16StringView&amp;lt;S&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                   ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fatal error: too many errors emitted, stopping now &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-ferror-limit&lt;span style=&#34;color:#f92672&#34;&gt;=]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; warnings and &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; errors generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make: *** &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;transliterator.o&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Error &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make failed, exit code &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Gem files will remain installed in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/charlock_holmes-0.7.9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; inspection.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Results logged to
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/extensions/arm64-darwin-24/3.4.0/charlock_holmes-0.7.9/gem_make.out
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:126:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::Builder.run&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:52:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block in Gem::Ext::Builder.make&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:44:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Array#each&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:44:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::Builder.make&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/ext_conf_builder.rb:44:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::ExtConfBuilder.build&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:195:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::Builder#build_extension&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:229:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block in Gem::Ext::Builder#build_extensions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:226:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Array#each&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:226:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::Builder#build_extensions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/installer.rb:844:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Installer#build_extensions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/rubygems_gem_installer.rb:76:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::RubyGemsGemInstaller#build_extensions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/rubygems_gem_installer.rb:28:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::RubyGemsGemInstaller#install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/source/rubygems.rb:203:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::Source::Rubygems#install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/installer/gem_installer.rb:54:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::GemInstaller#install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/installer/gem_installer.rb:16:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::GemInstaller#install_from_spec&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/installer/parallel_installer.rb:130:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::ParallelInstaller#do_install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/installer/parallel_installer.rb:121:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block in Bundler::ParallelInstaller#worker_pool&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/worker.rb:62:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::Worker#apply_func&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/worker.rb:57:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block in Bundler::Worker#process_queue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;internal:kernel&amp;gt;:168:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Kernel#loop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/worker.rb:54:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::Worker#process_queue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/worker.rb:90:in
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block (2 levels) in Bundler::Worker#create_threads&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;An error occurred &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; installing charlock_holmes &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;0.7.9&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;, and Bundler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cannot &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In Gemfile:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;will@lentil ~/clients/Outvote/repos/web-app/master &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;on master&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;% gem uninstall charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Gem &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;charlock_holmes&amp;#39;&lt;/span&gt; is not installed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;will@lentil ~/clients/Outvote/repos/web-app/master &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;on master&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;% git pull
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;will@lentil ~/clients/Outvote/repos/web-app/master &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;on master&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;% bundle
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Fetching gem metadata from https://enterprise.contribsys.com/..
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Fetching gem metadata from https://rubygems.org/........
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Installing charlock_holmes 0.7.9 with native extensions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    current directory: /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/charlock_holmes-0.7.9/ext/charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/bin/ruby extconf.rb --with-opt-dir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;/usr/local/opt --with-opt-include&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;/usr/local/opt/icu4c/include
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-opt-lib&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;/usr/local/opt/icu4c/lib --with-cxxflags&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;-std&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;c++11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; pkg-config &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu-i18n... &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I/opt/homebrew/Cellar/icu4c@77/77.1/include &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-L/opt/homebrew/Cellar/icu4c@77/77.1/lib&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-licui18n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; pkg-config &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu-io... &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I/opt/homebrew/Cellar/icu4c@77/77.1/include &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-L/opt/homebrew/Cellar/icu4c@77/77.1/lib&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-licuio&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; pkg-config &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu-uc... &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I/opt/homebrew/Cellar/icu4c@77/77.1/include &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-L/opt/homebrew/Cellar/icu4c@77/77.1/lib&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-licuuc&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -licui18n... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; unicode/ucnv.h... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -lz... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -licuuc... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -licudata... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu that requires explicit C++ version flag... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; icu that compiles with c++20 standard... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Static linking is disabled.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;creating Makefile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current directory: /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/charlock_holmes-0.7.9/ext/charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make DESTDIR&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt; sitearchdir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;./.gem.20250529-48158-xjue2n sitelibdir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;./.gem.20250529-48158-xjue2n clean
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current directory: /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/charlock_holmes-0.7.9/ext/charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make DESTDIR&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt; sitearchdir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;./.gem.20250529-48158-xjue2n sitelibdir&lt;span style=&#34;color:#ae81ff&#34;&gt;\=&lt;/span&gt;./.gem.20250529-48158-xjue2n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling converter.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from converter.c:2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ./common.h:9:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby.h:38:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/ruby.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/internal/anyargs.h:83:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:6: warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MAJOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:37: warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MINOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                     ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; warnings generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling encoding_detector.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from encoding_detector.c:2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ./common.h:9:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby.h:38:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/ruby.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/internal/anyargs.h:83:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:6: warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MAJOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:37: warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MINOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                     ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; warnings generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling ext.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ext.c:1:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ./common.h:9:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby.h:38:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/ruby.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/internal/anyargs.h:83:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:6: warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MAJOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/include/ruby-3.4.0/ruby/backward/cxxanyargs.hpp:540:37: warning: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RUBY_API_VERSION_MINOR&amp;#39;&lt;/span&gt; is not defined, evaluates to &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wundef&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;540&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) &amp;gt;= 301&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                     ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; warnings generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling transliterator.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:15:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/utypes.h:39:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/uversion.h:182:11: warning: nested namespace definition is a C++17 extension; define each namespace separately
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wc++17-extensions&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;182&lt;/span&gt; | namespace U_HEADER_ONLY_NAMESPACE &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |           ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/uversion.h:180:48: note: expanded from macro &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;U_HEADER_ONLY_NAMESPACE&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;180&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#define U_HEADER_ONLY_NAMESPACE U_ICU_NAMESPACE::U_HEADER_NESTED_NAMESPACE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:271:38: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;271&lt;/span&gt; | template&amp;lt;typename T, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;std::is_same_v&amp;lt;T, UChar&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                 ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:271:55: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same_v&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;; did you mean &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;271&lt;/span&gt; | template&amp;lt;typename T, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;std::is_same_v&amp;lt;T, UChar&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                  ~~~~~^~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                       is_same
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_same.h:22:29: note: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt; declared here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; | struct _LIBCPP_TEMPLATE_VIS is_same : _BoolConstant&amp;lt;__is_same&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;_Tp, _Up&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:273:8: warning: constexpr &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; is a C++17 extension &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wc++17-extensions&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;273&lt;/span&gt; |     &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; constexpr &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;std::is_same_v&amp;lt;UChar, char16_t&amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |        ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:273:24: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same_v&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;; did you mean &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;273&lt;/span&gt; |     &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; constexpr &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;std::is_same_v&amp;lt;UChar, char16_t&amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                   ~~~~~^~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                        is_same
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_same.h:22:29: note: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt; declared here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; | struct _LIBCPP_TEMPLATE_VIS is_same : _BoolConstant&amp;lt;__is_same&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;_Tp, _Up&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:273:50: error: expected unqualified-id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;273&lt;/span&gt; |     &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; constexpr &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;std::is_same_v&amp;lt;UChar, char16_t&amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                  ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:385:16: warning: variable templates are a C++14 extension &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wc++14-extensions&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;385&lt;/span&gt; | constexpr bool ConvertibleToU16StringView &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:386:10: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_convertible_v&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;; did you mean &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_convertible&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;386&lt;/span&gt; |     std::is_convertible_v&amp;lt;T, std::u16string_view&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |     ~~~~~^~~~~~~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |          is_convertible
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_convertible.h:22:29: note: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_convertible&amp;#39;&lt;/span&gt; declared here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; | struct _LIBCPP_TEMPLATE_VIS is_convertible : public integral_constant&amp;lt;bool, __is_convertible&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;_T1, _T2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:37:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:393:5: error: expected &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;(&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;-style cast or type construction
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;386&lt;/span&gt; |     std::is_convertible_v&amp;lt;T, std::u16string_view&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;387&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if !U_CHAR16_IS_TYPEDEF &amp;amp;&amp;amp; (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION &amp;lt; 180000)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;388&lt;/span&gt; |     &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; std::is_convertible_v&amp;lt;T, std::basic_string_view&amp;lt;uint16_t&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;389&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;390&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#if U_SIZEOF_WCHAR_T==2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;391&lt;/span&gt; |     &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; std::is_convertible_v&amp;lt;T, std::wstring_view&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;392&lt;/span&gt; | &lt;span style=&#34;color:#75715e&#34;&gt;#endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;393&lt;/span&gt; |     ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |     ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:429:36: error: no type named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;429&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename std::enable_if_t&amp;lt;!std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                      ~~~~~~~~~~~~~~^~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:429:47: error: expected &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt; or &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;gt;&amp;#39;&lt;/span&gt; in template-parameter-list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;429&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename std::enable_if_t&amp;lt;!std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                               ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:429:93: error: expected unqualified-id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;429&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename std::enable_if_t&amp;lt;!std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                                                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:439:36: error: no type named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;439&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename std::enable_if_t&amp;lt;std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                      ~~~~~~~~~~~~~~^~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:439:47: error: expected &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt; or &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;gt;&amp;#39;&lt;/span&gt; in template-parameter-list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;439&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename std::enable_if_t&amp;lt;std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                               ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/char16ptr.h:439:92: error: expected unqualified-id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;439&lt;/span&gt; |           typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; typename std::enable_if_t&amp;lt;std::is_pointer_v&amp;lt;std::remove_reference_t&amp;lt;T&amp;gt;&amp;gt;&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                                                            ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:40:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/stringpiece.h:134:29: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;134&lt;/span&gt; |             typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                        ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/stringpiece.h:135:23: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same_v&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;; did you mean &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;135&lt;/span&gt; |                 &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;std::is_same_v&amp;lt;decltype&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;.data&lt;span style=&#34;color:#f92672&#34;&gt;())&lt;/span&gt;, const char*&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                  ~~~~~^~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                       is_same
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__type_traits/is_same.h:22:29: note: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;is_same&amp;#39;&lt;/span&gt; declared here
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; | struct _LIBCPP_TEMPLATE_VIS is_same : _BoolConstant&amp;lt;__is_same&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;_Tp, _Up&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                             ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:40:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/stringpiece.h:140:17: error: use of address-of-label extension outside of a &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; body
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;140&lt;/span&gt; |                 std::is_same_v&amp;lt;decltype&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;.size&lt;span style=&#34;color:#f92672&#34;&gt;())&lt;/span&gt;, size_t&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                 ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/stringpiece.h:140:62: error: expected member name or &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt; after declaration specifiers
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;140&lt;/span&gt; |                 std::is_same_v&amp;lt;decltype&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;.size&lt;span style=&#34;color:#f92672&#34;&gt;())&lt;/span&gt;, size_t&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                                              ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from transliterator.cpp:5:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from /opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/translit.h:27:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:346:40: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;346&lt;/span&gt; |   template&amp;lt;typename S, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;ConvertibleToU16StringView&amp;lt;S&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                   ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:381:40: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;381&lt;/span&gt; |   template&amp;lt;typename S, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;ConvertibleToU16StringView&amp;lt;S&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                   ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/opt/homebrew/Cellar/icu4c@77/77.1/include/unicode/unistr.h:1959:40: error: no template named &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;enable_if_t&amp;#39;&lt;/span&gt; in namespace &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;std&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1959&lt;/span&gt; |   template&amp;lt;typename S, typename &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; std::enable_if_t&amp;lt;ConvertibleToU16StringView&amp;lt;S&amp;gt;&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      |                                   ~~~~~^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fatal error: too many errors emitted, stopping now &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-ferror-limit&lt;span style=&#34;color:#f92672&#34;&gt;=]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; warnings and &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; errors generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make: *** &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;transliterator.o&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Error &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make failed, exit code &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Gem files will remain installed in /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/charlock_holmes-0.7.9 &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; inspection.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Results logged to /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/extensions/arm64-darwin-24/3.4.0/charlock_holmes-0.7.9/gem_make.out
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:126:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::Builder.run&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:52:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block in Gem::Ext::Builder.make&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:44:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Array#each&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:44:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::Builder.make&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/ext_conf_builder.rb:44:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::ExtConfBuilder.build&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:195:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::Builder#build_extension&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:229:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block in Gem::Ext::Builder#build_extensions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:226:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Array#each&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/ext/builder.rb:226:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Ext::Builder#build_extensions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/3.4.0/rubygems/installer.rb:844:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Gem::Installer#build_extensions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/rubygems_gem_installer.rb:76:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::RubyGemsGemInstaller#build_extensions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/rubygems_gem_installer.rb:28:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::RubyGemsGemInstaller#install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/source/rubygems.rb:203:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::Source::Rubygems#install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/installer/gem_installer.rb:54:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::GemInstaller#install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/installer/gem_installer.rb:16:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::GemInstaller#install_from_spec&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/installer/parallel_installer.rb:130:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::ParallelInstaller#do_install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/installer/parallel_installer.rb:121:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Bundler::ParallelInstaller#worker_pool&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/worker.rb:62:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::Worker#apply_func&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/worker.rb:57:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block in Bundler::Worker#process_queue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;internal:kernel&amp;gt;:168:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Kernel#loop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/worker.rb:54:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Bundler::Worker#process_queue&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  /Users/will/.rbenv/versions/3.4.3/lib/ruby/gems/3.4.0/gems/bundler-2.4.22/lib/bundler/worker.rb:90:in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block (2 levels) in Bundler::Worker#create_threads&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;An error occurred &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; installing charlock_holmes &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;0.7.9&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;, and Bundler cannot &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In Gemfile:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Try installing using a newer c++ standard:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gem install charlock_holmes -v&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0.7.9 -- --with-opt-dir&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/local/opt --with-opt-include&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/local/opt/icu4c/include --with-opt-lib&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/local/opt/icu4c/lib --with-cxxflags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;-std&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;c++17
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building native extensions with: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;--with-opt-dir=/usr/local/opt --with-opt-include=/usr/local/opt/icu4c/include --with-opt-lib=/usr/local/opt/icu4c/lib --with-cxxflags=-std=c++17&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;This could take a &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Successfully installed charlock_holmes-0.7.9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; gem installed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
      
      
      
      <item>
      <title>Final robot photos</title>
      <link>https://willj.net/posts/final-robot-photos/</link>
      <pubDate>Tue, 06 Aug 2024 10:00:00 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/final-robot-photos/</guid>
      <description>&lt;p&gt;I spent several months iterating on the design and build of a ping pong ball collecting robot back in about 2014 but never posted the final photos of it anywhere, these are the final photos I took of the finished robot.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/final-robot-photos/images/IMG_0594.JPG&#34;
    alt=&#34;A robot view from the front left, a hopper full of ping pong balls on it&amp;#39;s back&#34;&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/final-robot-photos/images/IMG_0595.JPG&#34;
    alt=&#34;Side view of the robot, wire bundle out the back&#34;&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>You should use the Ruby on Rails logger block syntax</title>
      <link>https://willj.net/posts/you-should-use-the-rails-logger-block-syntax/</link>
      <pubDate>Wed, 31 Jul 2024 17:00:00 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/you-should-use-the-rails-logger-block-syntax/</guid>
      <description>&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Passing strings to the Rails logger methods (eg. &lt;code&gt;Rails.logger.info(…)&lt;/code&gt;) causes unecessary object allocations, and if you&amp;rsquo;re calling methods to generate data for your log messages then it can cause unecessary CPU work too. In this post I&amp;rsquo;ll show you how to use block syntax when using your logger with Rails to save object allocations and CPU time.&lt;/p&gt;
&lt;h2 id=&#34;the-context&#34;&gt;The Context&lt;/h2&gt;
&lt;p&gt;When you&amp;rsquo;re logging in Ruby on Rails log messages sent with a level above the currently configured log level will not be logged. The default in production is to log at &lt;code&gt;info&lt;/code&gt; or below, so anything logged at debug level will not be output to the logs:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;debug  ⬆️ Ignored
-----------------
info   ⬇️  Logged
warn
error
fatal
unknown
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The log level can be set in the environment configs, from &lt;code&gt;config/environments/production.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;log_level &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ENV&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fetch(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;RAILS_LOG_LEVEL&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;info&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The log level can also be changed at any time, including in the Rails console, by setting the log level directly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Rails&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;level &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:warn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:warn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-problem---object-allocations-for-unused-logs&#34;&gt;The problem - Object allocations for unused logs&lt;/h2&gt;
&lt;aside&gt;
For these examples going to be using the excellent &lt;a href=&#34;https://github.com/srawlins/allocation_stats&#34;&gt;allocation_stats ruby gem&lt;/a&gt; to get object allocation counts.
&lt;/aside&gt;
&lt;p&gt;Let&amp;rsquo;s say you want to log some debug data for an API call that a user is making. You might do something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Rails&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;debug &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Processed API request to host &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;somehost&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; for user \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; (&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;): status: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;request_status&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; user_details: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;to_json&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You push this code to production, it&amp;rsquo;s useful to have a way to debug user API issues just by setting the Rails log level to &lt;code&gt;debug&lt;/code&gt; from &lt;code&gt;info&lt;/code&gt; using the &lt;code&gt;RAILS_LOG_LEVEL&lt;/code&gt; environment variable, you can always set it back to &lt;code&gt;info&lt;/code&gt; when you&amp;rsquo;re done. Let&amp;rsquo;s look at what this statement allocates when the application is logging at the &lt;code&gt;debug&lt;/code&gt; level:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set the log level&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Rails&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;level &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:debug&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:debug&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Do the logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; stats &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;AllocationStats&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;trace {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;Rails&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;debug &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Processed API request to \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      host &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;somehost&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; for user &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; (&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;): status: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;request_status&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      user_details: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;to_json&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Processed&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;API&lt;/span&gt; request to host &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; user &lt;span style=&#34;color:#66d9ef&#34;&gt;Slartibartfast&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;): &lt;span style=&#34;color:#e6db74&#34;&gt;status&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;DENIED&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;user_details&lt;/span&gt;: {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:&amp;#34;Slartibartfast&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:&amp;#34;s.bartfast@magrathea.biz&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;favourite_colour&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:&amp;#34;blue&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&amp;lt;AllocationStats::Allocation:0x000000015489fe18 @object=#&amp;lt;Proc:0x000000015471e9e0 activesupport-7.1.3.4/lib/active_support/broadcas...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Get an allocation count, source paths shortened for brevity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; puts stats&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;allocations&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;group_by(&lt;span style=&#34;color:#e6db74&#34;&gt;:sourcefile&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:sourceline&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:class&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;to_text
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           sourcefile                             sourceline                      &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;                      count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-----------------------------------------------------------------&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;----------&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;---------------------------------------------&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;broadcast_logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb             &lt;span style=&#34;color:#ae81ff&#34;&gt;231&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Proc&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(irb)                                                                     &lt;span style=&#34;color:#ae81ff&#34;&gt;45&lt;/span&gt;  Array                                              &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ruby&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;common&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                                                &lt;span style=&#34;color:#ae81ff&#34;&gt;303&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;JSON&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Ext&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Generator&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;State&lt;/span&gt;                        &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;core_ext&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;object&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb         &lt;span style=&#34;color:#ae81ff&#34;&gt;188&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;encoding&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                 &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;ActiveSupport&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;JSON&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Encoding&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;JSONGemEncoder&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(irb)                                                                     &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(irb)                                                                     &lt;span style=&#34;color:#ae81ff&#34;&gt;45&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;internal&lt;/span&gt;:timev&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                                                         &lt;span style=&#34;color:#ae81ff&#34;&gt;226&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Time&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ruby&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;common&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                                                &lt;span style=&#34;color:#ae81ff&#34;&gt;305&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;encoding&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                 &lt;span style=&#34;color:#ae81ff&#34;&gt;92&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;encoding&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                 &lt;span style=&#34;color:#ae81ff&#34;&gt;77&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;core_ext&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;object&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb         &lt;span style=&#34;color:#ae81ff&#34;&gt;186&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;core_ext&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;object&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb          &lt;span style=&#34;color:#ae81ff&#34;&gt;78&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;encoding&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                 &lt;span style=&#34;color:#ae81ff&#34;&gt;33&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ruby&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;log_device&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                                           &lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                        &lt;span style=&#34;color:#ae81ff&#34;&gt;38&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ruby&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;log_device&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                                          &lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;File&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Stat&lt;/span&gt;                                         &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is fine! We&amp;rsquo;re logging some data, the Ruby VM is doing work and allocates objects. Let&amp;rsquo;s look at what happens when we change the log level to &lt;code&gt;info&lt;/code&gt; when we&amp;rsquo;re done debugging:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set the log level&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Rails&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;level &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:info&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:info&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Do the logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; stats &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;AllocationStats&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;trace {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;Rails&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;debug &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Processed API request to \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      host &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;somehost&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; for user &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; (&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;): status: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;request_status&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      user_details: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;to_json&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&amp;lt;AllocationStats::Allocation:0x000000015489fd28 @object=#&amp;lt;Proc:0x000000015471e648 activesupport-7.1.3.4/lib/active_support/broadcas...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Get an allocation count, source paths shortened for brevity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; puts stats&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;allocations&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;group_by(&lt;span style=&#34;color:#e6db74&#34;&gt;:sourcefile&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:sourceline&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:class&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;to_text
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           sourcefile                              sourceline                      &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;                      count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-----------------------------------------------------------------&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;----------&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;---------------------------------------------&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;broadcast_logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb              &lt;span style=&#34;color:#ae81ff&#34;&gt;231&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Proc&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(irb)                                                                      &lt;span style=&#34;color:#ae81ff&#34;&gt;48&lt;/span&gt;  Array                                              &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Users&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;will&lt;span style=&#34;color:#f92672&#34;&gt;/.&lt;/span&gt;rbenv&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;versions&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;ruby&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;common&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb           &lt;span style=&#34;color:#ae81ff&#34;&gt;303&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;JSON&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Ext&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Generator&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;State&lt;/span&gt;                        &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;core_ext&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;object&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb          &lt;span style=&#34;color:#ae81ff&#34;&gt;188&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;encoding&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                  &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;ActiveSupport&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;JSON&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Encoding&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;JSONGemEncoder&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(irb)                                                                      &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(irb)                                                                      &lt;span style=&#34;color:#ae81ff&#34;&gt;48&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Users&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;will&lt;span style=&#34;color:#f92672&#34;&gt;/.&lt;/span&gt;rbenv&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;versions&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;ruby&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;common&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb           &lt;span style=&#34;color:#ae81ff&#34;&gt;305&lt;/span&gt;  String                                             &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;encoding&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                  &lt;span style=&#34;color:#ae81ff&#34;&gt;92&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;encoding&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                  &lt;span style=&#34;color:#ae81ff&#34;&gt;77&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;core_ext&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;object&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb          &lt;span style=&#34;color:#ae81ff&#34;&gt;186&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;core_ext&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;object&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb           &lt;span style=&#34;color:#ae81ff&#34;&gt;78&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;json&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;encoding&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb                  &lt;span style=&#34;color:#ae81ff&#34;&gt;33&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Hash&lt;/span&gt;                                               &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code didn&amp;rsquo;t log anything beacuse the log level is set to &lt;code&gt;info&lt;/code&gt; and we called the &lt;code&gt;debug&lt;/code&gt; log level method, however &lt;strong&gt;we still allocated almost as many objects!&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;why-this-happens&#34;&gt;Why this happens&lt;/h2&gt;
&lt;p&gt;When we call &lt;code&gt;Rails.logger.debug&lt;/code&gt; with a string, say &lt;code&gt;&amp;quot;Hello #{name}, here&#39;s some #{generated_data}!&amp;quot;&lt;/code&gt;, the string is created as an object, including any interpolation that is required which may include methods that are called to retrieve or generate the data which also allocates objects. This happens before the string is passed to the method &lt;em&gt;regardless of the current log level&lt;/em&gt;, it is up to the logger when passed this now created string to decide if it is going to log it or not. That&amp;rsquo;s wasteful!&lt;/p&gt;
&lt;h2 id=&#34;the-solution-passing-a-block-to-the-logger&#34;&gt;The solution, passing a block to the logger&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s run that debug code again but this time pass a block to the logger:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set the log level&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Rails&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;level &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:info&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:info&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Do the logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; stats &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;AllocationStats&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;trace {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;Rails&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;debug { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Processed API request to \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      host &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;somehost&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; for user &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; (&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;): status: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;request_status&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      user_details: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;user&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;to_json&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&amp;lt;AllocationStats::Allocation:0x000000015489ffa8 @object=#&amp;lt;Proc:0x000000015471ea58 /Users/will/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/broadcas...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Get an allocation count, source paths shortened for brevity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; puts stats&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;allocations&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;group_by(&lt;span style=&#34;color:#e6db74&#34;&gt;:sourcefile&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:sourceline&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:class&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;to_text
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          sourcefile                          sourceline  &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;  count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;------------------------------------------------------------&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;----------&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-----&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;activesupport&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;active_support&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;broadcast_logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rb         &lt;span style=&#34;color:#ae81ff&#34;&gt;231&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Proc&lt;/span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(irb)                                                                 &lt;span style=&#34;color:#ae81ff&#34;&gt;51&lt;/span&gt;  Array      &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s a lot better, we&amp;rsquo;re still not logging anything but the allocations are now significantly reduced. Ideally we&amp;rsquo;d allocate zero objects when logging nothing, but allocating three is a lot better than what we were allocationg before.&lt;/p&gt;
&lt;p&gt;This works because when you pass a block to the logger method (&lt;code&gt;debug&lt;/code&gt; in this case) the block will only be called if the log level is currently being logged. We had set the log level to &lt;code&gt;info&lt;/code&gt; which meant that the block passed to the &lt;code&gt;debug&lt;/code&gt; method was never called, and the object allocations to generate the string never happened.&lt;/p&gt;
&lt;h2 id=&#34;why-should-i-care&#34;&gt;Why should I care?&lt;/h2&gt;
&lt;p&gt;The examples given here are admittedly trivial (and a little contrived to show the difference), and for an application that doesn&amp;rsquo;t log much or doesn&amp;rsquo;t get much traffic then the benefit is going to be tiny, but the effort involved in making the change to block syntax is &lt;em&gt;really&lt;/em&gt; small, it&amp;rsquo;s not detrimental to the code readability either. Small applications can eventually grow into large ones, a handful of requests per second can change to thousands, and if that happens the block syntax can make a difference and you&amp;rsquo;ll likely be glad you made it a habit.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Finding Postgres rows too large for BTree indexes</title>
      <link>https://willj.net/posts/finding-postgres-rows-too-large-for-btree-indexes/</link>
      <pubDate>Sat, 17 Feb 2024 17:25:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/finding-postgres-rows-too-large-for-btree-indexes/</guid>
      <description>&lt;p&gt;We are currently migrating our main application database from AWS Aurora Postgres to Google AlloyDB Postgres (it&amp;rsquo;s a cost decision) and I&amp;rsquo;m using Google&amp;rsquo;s database Migration tool to do the work. At some point last week the migration failed on Google&amp;rsquo;s side with an error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;index row size 2712 exceeds btree version 4 maximum 2704 for index index_name_column_name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;ve not seen this before, but it was easy to find the problem rows affecting this specific index/column:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;table_name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;octet_length&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;column_name&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2704&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simple enough, out popped 5 rows where the data in &lt;code&gt;column_name&lt;/code&gt; was too large. This data was junk so NULLing it out fixed the bad data I knew about, but I wanted to make sure that there weren&amp;rsquo;t more indexes with this issue, replicating our database to AlloyDB takes time and egress cost from AWS so fixing any known issues before we do this makes a lot of sense. To do this I wrote this Ruby program. The program scans through all column combinations for each table where the combined data &lt;em&gt;could&lt;/em&gt; be too large for an index and outputs a warning if the data it finds &lt;em&gt;is&lt;/em&gt; too large, allowing you to then run a select to get the specific data that caused the problem.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This code is MIT licensed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;require &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dsn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ARGV&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;PG&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;connect(dsn)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# So our postgres array gets converted to a Ruby array&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;type_map_for_results &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;PG&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;BasicTypeMapForResults&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;new(conn)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# I&amp;#39;ve seen various figures for the maximum index entry size including 2712&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# bytes, 2713 bytes, and block_size/3 (which for the default block size of 8 kB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# is ~2730 bytes), however 2704 bytes is the figure given by the error from&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# AlloyDB, so is the one we&amp;#39;re using here.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You might need to change this value if you are using a different block size.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;max_index_size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2704&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create a cache for column size lookups. Column sizes will be in two types:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#   1. &amp;#34;static&amp;#34; types, eg. int. These won&amp;#39;t change no-matter what data is stored&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#      in them so we can just return the size for the type, eg. int =&amp;gt; 4 bytes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#   2. &amp;#34;dynamic&amp;#34; types, eg. text. The octet_length of these will change&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#      depending on what is stored in them, and so we can&amp;#39;t store a fixed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#      integer byte size and need to scan the database to find the max size. As&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#      such rather than storing a fixed size we will store the query to find the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#      max length.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# We cache the values as we will be doing the opereration per index, and for the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# same table a column can appear in multiple indexes, but the static/dynamic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# nature of the column will not changed so we can save a little work by cacheing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# the result.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@column_type_length_cache &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Query to find all indexes in the &amp;#39;public&amp;#39; schema that contain columns that are&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# &amp;#34;dynamic&amp;#34;, eg. text or jsonb expressions. Indexes that contain &amp;#34;static&amp;#34; data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# types, eg. integer alone aren&amp;#39;t interesting as it&amp;#39;s unlikely that you will&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# exceed the max BTree index entry size with things like UUIDs or integers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# alone.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;query_indexes &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    t&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;relname &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; table_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ix&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;relname &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; index_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;ARRAY_AGG&lt;/span&gt;(a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;attname) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; column_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;CASE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;WHEN&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;indexprs &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;THEN&lt;/span&gt; pg_get_expr(i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;indexprs, i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;indrelid)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;ELSE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;END&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; index_expression
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pg_class t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_catalog&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pg_index i &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; t&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;indrelid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_catalog&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pg_class ix &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; ix&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;indexrelid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_attribute a &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;attrelid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; t&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;attnum &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ANY&lt;/span&gt; (i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;indkey)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_am am &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; am&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ix&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;relam
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;indexrelid &lt;span style=&#34;color:#66d9ef&#34;&gt;IN&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Select&lt;/span&gt; any indexes that contain at least one field type we care about,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; excluding field types that we know, &lt;span style=&#34;color:#66d9ef&#34;&gt;when&lt;/span&gt; used alone, will &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; be larger
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; than an index entry, &lt;span style=&#34;color:#66d9ef&#34;&gt;unless&lt;/span&gt; you are doing something especially fruity&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        distinct(c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      pg_catalog&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pg_class c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_catalog&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pg_index i &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;indexrelid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_catalog&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pg_namespace ns &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;relnamespace &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ns&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_catalog&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pg_attribute a &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;attrelid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        relkind &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;i&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; indisprimary &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;FALSE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; ns&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;nspname &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;public&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;atttypid &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;IN&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;,   &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; boolean
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;,   &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; bigint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt;,   &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; smallint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;,   &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; integer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;1082&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; date
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;1114&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; timestamp without timezone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#ae81ff&#34;&gt;2950&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; uuid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; am&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;amname &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;btree&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt; I am only concerned about btree types as that was the error we are dealing with
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;GROUP&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; table_name, index_name, index_expression
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;indexes_result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;exec(query_indexes)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:values&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;column_octet_length_query&lt;/span&gt;(conn, column)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;max(octet_length(&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;quote_ident(column)&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;))&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;expression_octet_length_query&lt;/span&gt;(expression)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;max(octet_length(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;expression&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;))&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fetch_column_type_length&lt;/span&gt;(conn, table_name, column_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cache_key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;table_name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;column_name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# We can have multiple indexes on the same table that reference the same&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# column so let&amp;#39;s cache the lookups for a column&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @column_type_length_cache&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;cache_key&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    query &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;atttypid,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        t&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;typlen
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; pg_attribute a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_type t &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;atttypid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; t&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; pg_class c &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;attrelid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;oid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;relname &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $1 &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; a&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;attname &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;exec_params(query, &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;table_name, column_name&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    typlen &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; result&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;first&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;typlen&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;].&lt;/span&gt;to_i
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    typlen&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;positive? ? typlen : column_octet_length_query(conn, column_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;indexes_result&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;each &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;table_name, index_name, column_names, index_expression&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  index_expression &lt;span style=&#34;color:#f92672&#34;&gt;||=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    regular_column_size_queries &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; column_names&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map { &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;cn&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; fetch_column_type_length(conn, table_name, cn) }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expression_size_queries &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; index_expression&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;split(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map { &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;e&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; expression_octet_length_query(e) }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    all_size_queries_string &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (regular_column_size_queries &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; expression_size_queries)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;join(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; + &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    compound_size_query &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;all_size_queries_string&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; AS max_size FROM &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;quote_ident(table_name)&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    max_size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;exec(compound_size_query)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;first&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;max_size&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;].&lt;/span&gt;to_i
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; max_size &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; max_index_size
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      puts &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\033&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[31mWARNING: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;table_name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; (&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;index_name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;): &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;column_names&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;join(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;, &amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;: Maximum Size: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;max_size&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; bytes exceeds the max index size&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\033&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;[0m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;rescue&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;PG&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;InsufficientPrivilege&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# We have some tables that I can&amp;#39;t access with the user this runs as, but I don&amp;#39;t care about them.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    puts &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Permission denied for table &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#{&lt;/span&gt;table_name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;close
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You run it using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ruby script_name.rb your_postgres_dsn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It may take quite a lot of time to run, it effectively sequential scans all of your tables where there is a row that could be larger than the allowed row size for a BTree index, and as such you may want to run it against a replica and/or out of hours to avoid production impact, but other than that it&amp;rsquo;s safe. For us it did find about a hundred rows in another table that were too large for the index allowing us to fix these before re-starting the migration process.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WARNING: some_other_table (some_index_name_idx): user_id, email, phone, approved: Maximum Size: 28586 bytes exceeds the max index size
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yeah, some people had suspiciously long emails. We&amp;rsquo;re adding size constraints on the columns that were missing them now. If you get a warning like this then you can craft a query to find the problem rows, eg.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; some_other_table &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;octet_length&lt;/span&gt;(email) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;octet_length&lt;/span&gt;(phone) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2704&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Some highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The program will sum the octet_length of all fields in an index, so if you have an index with two columns in it and it&amp;rsquo;s only the sum of the octet_lengths that will push the row over the BTree row size this program will still find the issue.&lt;/li&gt;
&lt;li&gt;The program prunes indexes and tables where there are no indexes that could be large enough to be over the limit, effectively cutting the number of table scans it needs to do. If you&amp;rsquo;ve got an index with 677 int fields in it then the assumption this relies on will break down, but I&amp;rsquo;ve never seen that, and never want to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some caveats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Table names and column names are escaped, but don&amp;rsquo;t run this if you have untrusted third-parties who can control any expressions you have in your database. For instance if you&amp;rsquo;re indexing into JSON with a user supplied key, eg. &lt;code&gt;(comments -&amp;gt;&amp;gt; &#39;user_supplied_value&#39;::text)&lt;/code&gt;. You&amp;rsquo;re probably not doing this, I&amp;rsquo;ve never seen it, but just be aware.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This program finds rows that violate the size constraints, it doesn&amp;rsquo;t find situations where a row &lt;em&gt;could&lt;/em&gt; violate the size limit if you were to put in the maximum amount of data allowed by the types.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I believe this program works if you are indexing into multiple JSONB fields in one index, but I&amp;rsquo;ve not tested it with those as we only have indexes into a single JSONB field, eg:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;quot;index_name&amp;quot; btree (some_id, (comments -&amp;gt;&amp;gt; &#39;some_key&#39;::text))
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please let me know if you run this and have success and/or issues, or if you come up with a more efficient way of doing the same thing.&lt;/p&gt;
</description>
    </item>
    
      
      
      
      
      
      <item>
      <title>Measuring IO timings when using EXPLAIN ANALYSE in Postgres</title>
      <link>https://willj.net/posts/measuring-io-timing-for-postgres-explain-analyse/</link>
      <pubDate>Tue, 19 Sep 2023 23:21:00 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/measuring-io-timing-for-postgres-explain-analyse/</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://willj.net/posts/buffer-analysis-when-using-explain-analyse-in-postgres&#34;&gt;an earlier post about using &lt;code&gt;BUFFERS&lt;/code&gt; with &lt;code&gt;EXPLAIN ANALYSE&lt;/code&gt;&lt;/a&gt; I mentioned that there were a couple of options to &lt;code&gt;EXPLAIN ANALYSE&lt;/code&gt; that were not widely known, but I only talked about one, the &lt;code&gt;BUFFERS&lt;/code&gt; option. In this article I will dig into that second option; IO timing tracking.&lt;/p&gt;
&lt;h2 id=&#34;io-timing-tracking&#34;&gt;IO timing tracking&lt;/h2&gt;
&lt;p&gt;The second tweak to the default &lt;code&gt;EXPLAIN&lt;/code&gt; usage is using IO timing tracking. You can set this per session:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set track_io_timing = on;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As usual &lt;a href=&#34;https://www.postgresql.org/docs/current/runtime-config-statistics.html&#34;&gt;the Postgres docs do a thorough job explaining what this setting does&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enables timing of database I/O calls. This parameter is off by default, as it will repeatedly query the operating system for the current time, which may cause significant overhead on some platforms. You can use the pg_test_timing tool to measure the overhead of timing on your system. I/O timing information is displayed in pg_stat_database, in the output of EXPLAIN when the BUFFERS option is used, in the output of VACUUM when the VERBOSE option is used, by autovacuum for auto-vacuums and auto-analyzes, when log_autovacuum_min_duration is set and by pg_stat_statements. Only superusers and users with the appropriate SET privilege can change this setting.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;However simply put for our use case if you turn this setting on then when you run an &lt;code&gt;EXPLAIN (ANALYSE, BUFFERS)&lt;/code&gt; you will get the time in milliseconds that the IO operations in each part of your query took to perform, for example using one of the queries from the previous post:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;EXPLAIN&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;ANALYSE&lt;/span&gt;, BUFFERS)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events.&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;INNER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; activity_logs &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; events.activity_logs_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; activity_logs.id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	activity_logs.user_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;83463&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.date &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-04&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.duration &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; events.exception_id &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	date &lt;span style=&#34;color:#66d9ef&#34;&gt;ASC&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; NULLS &lt;span style=&#34;color:#66d9ef&#34;&gt;LAST&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	Sort  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;37&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;762&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;763&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Sort &lt;span style=&#34;color:#66d9ef&#34;&gt;Key&lt;/span&gt;: events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; NULLS &lt;span style=&#34;color:#66d9ef&#34;&gt;LAST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Sort &lt;span style=&#34;color:#66d9ef&#34;&gt;Method&lt;/span&gt;: quicksort  Memory: &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1166&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3117&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;  I&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;O Timings: &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3221&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;979&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  Nested Loop  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;35&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;757&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;758&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1166&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3117&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;        I&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;O Timings: &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3221&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;979&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; index_activity_logs_on_user_id_and_event_start_and_event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt; activity_logs  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;56&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;325&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;82&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;018&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;964&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;315&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Cond: (user_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;83463&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;33&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;              I&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;O Timings: &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;137&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;986&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; index_events_on_activity_logs_id &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt; events  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;57&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;119&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;221&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;221&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;315&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Cond: (activity_logs_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; activity_logs.id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              Filter: ((((event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (duration &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::double &lt;span style=&#34;color:#66d9ef&#34;&gt;precision&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; (exception_id &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (date &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-04&amp;#39;&lt;/span&gt;::date))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#66d9ef&#34;&gt;Rows&lt;/span&gt; Removed &lt;span style=&#34;color:#66d9ef&#34;&gt;by&lt;/span&gt; Filter: &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1133&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;              I&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;O Timings: &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3083&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;993&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;146&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Planning Time: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;427&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Execution Time: &lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;813&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As with the &lt;code&gt;BUFFERS&lt;/code&gt; option the timings are cumulative at each node in the hierarchy of the explain output.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t something that I&amp;rsquo;ve personally found particularly useful, I suspect it might be useful when diagnosing slow fetches if you&amp;rsquo;re storing data on different backend data stores across tables, but it&amp;rsquo;s interesting to see.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Buffer analysis when using EXPLAIN ANALYSE in Postgres</title>
      <link>https://willj.net/posts/buffer-analysis-when-using-explain-analyse-in-postgres/</link>
      <pubDate>Fri, 15 Sep 2023 23:49:00 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/buffer-analysis-when-using-explain-analyse-in-postgres/</guid>
      <description>&lt;p&gt;Many people are familiar with running &lt;code&gt;EXPLAIN&lt;/code&gt; and &lt;code&gt;EXPLAIN ANALYSE&lt;/code&gt; to diagnose Postgres performance issues, but there are a couple of useful options available when running these reports that aren&amp;rsquo;t always commonly known that you might find useful. The first of these is the &lt;code&gt;BUFFERS&lt;/code&gt; option.&lt;/p&gt;
&lt;p&gt;In this article I will explain how to measure buffer usage in Postgres using the &lt;code&gt;BUFFERS&lt;/code&gt; option, and how I used it to help verify that a query optimization to massively reduce the IO demands of a problem query had worked.&lt;/p&gt;
&lt;h2 id=&#34;the-buffers-option&#34;&gt;The BUFFERS option&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;BUFFERS&lt;/code&gt; option can be used when running a simple &lt;code&gt;EXPLAIN&lt;/code&gt;, but really comes into it&amp;rsquo;s own when running an &lt;code&gt;EXPLAIN ANALYSE&lt;/code&gt;. In summary &lt;code&gt;BUFFERS&lt;/code&gt; will give you data on the buffer usage of a query. The postgres docs give a good description of what the data you get tells you:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Include information on buffer usage. Specifically, include the number of shared blocks hit, read, dirtied, and written, the number of local blocks hit, read, dirtied, and written, the number of temp blocks read and written, and the time spent reading and writing data file blocks and temporary file blocks (in milliseconds) if track_io_timing is enabled. A hit means that a read was avoided because the block was found already in cache when needed. Shared blocks contain data from regular tables and indexes; local blocks contain data from temporary tables and indexes; while temporary blocks contain short-term working data used in sorts, hashes, Materialize plan nodes, and similar cases. The number of blocks dirtied indicates the number of previously unmodified blocks that were changed by this query; while the number of blocks written indicates the number of previously-dirtied blocks evicted from cache by this backend during query processing. The number of blocks shown for an upper-level node includes those used by all its child nodes. In text format, only non-zero values are printed. It defaults to FALSE.&lt;/p&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.postgresql.org/docs/current/sql-explain.html&#34;&gt;https://www.postgresql.org/docs/current/sql-explain.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cutting down buffer usage can be a great way to decrease IO resource usage for a query.&lt;/p&gt;
&lt;h2 id=&#34;an-example&#34;&gt;An example&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at an example query. This is similar to one that I optimized for a client and the exact SQL/data structure isn&amp;rsquo;t important. Note the &lt;code&gt;EXPLAIN (ANALYSE, BUFFERS)&lt;/code&gt; line at the start of the query:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;EXPLAIN&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;ANALYSE&lt;/span&gt;, BUFFERS)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events.&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;INNER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; activity_logs &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; events.activity_logs_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; activity_logs.id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	activity_logs.user_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;83463&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.date &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-04&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.duration &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; events.exception_id &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	date &lt;span style=&#34;color:#66d9ef&#34;&gt;ASC&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; NULLS &lt;span style=&#34;color:#66d9ef&#34;&gt;LAST&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Sort  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;37&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;762&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;763&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Sort &lt;span style=&#34;color:#66d9ef&#34;&gt;Key&lt;/span&gt;: events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; NULLS &lt;span style=&#34;color:#66d9ef&#34;&gt;LAST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Sort &lt;span style=&#34;color:#66d9ef&#34;&gt;Method&lt;/span&gt;: quicksort  Memory: &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;  Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1166&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3117&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- (0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  Nested Loop  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;35&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;757&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;758&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;        Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1166&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3117&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;-- (1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; index_activity_logs_on_user_id_and_event_start_and_event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt; activity_logs  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;56&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;325&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;82&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;018&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;964&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;315&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Cond: (user_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;83463&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;              Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;33&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- (2)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; index_events_on_activity_logs_id &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt; events  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;57&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;119&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;221&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;221&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;315&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Cond: (activity_logs_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; activity_logs.id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              Filter: ((((event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (duration &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::double &lt;span style=&#34;color:#66d9ef&#34;&gt;precision&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; (exception_id &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (date &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-04&amp;#39;&lt;/span&gt;::date))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#66d9ef&#34;&gt;Rows&lt;/span&gt; Removed &lt;span style=&#34;color:#66d9ef&#34;&gt;by&lt;/span&gt; Filter: &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;              Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1133&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3001&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;-- (3)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;146&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Planning Time: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;427&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Execution Time: &lt;span style=&#34;color:#ae81ff&#34;&gt;2290&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;813&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a lot to take in here, but the difference you&amp;rsquo;re looking for compared to a regular &lt;code&gt;EXPLAIN&lt;/code&gt; output are the lines that start with &lt;code&gt;Buffers: …&lt;/code&gt; I&amp;rsquo;ve marked them all in the explain output above with the labels &lt;code&gt;(0)&lt;/code&gt;, &lt;code&gt;(1)&lt;/code&gt;, &lt;code&gt;(2)&lt;/code&gt; and &lt;code&gt;(3)&lt;/code&gt;. They look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Buffers: shared hit=1166 read=3117
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This line is telling us that &lt;strong&gt;1166 blocks were satisfied by the shared cache&lt;/strong&gt;, and &lt;strong&gt;3117 blocks were read from disk&lt;/strong&gt;.&lt;/p&gt;
&lt;aside class=&#34;thought&#34;&gt;
&lt;h3&gt;What is a block?&lt;/h3&gt;
&lt;p&gt;Blocks are chunks of data of a certain size. &lt;a href=&#34;https://www.postgresql.org/docs/current/runtime-config-preset.html&#34;&gt;The size is configurable, but is typically left at the default of 8192 bytes&lt;/a&gt;. You can check this on your server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;show&lt;/span&gt; block_size;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; block_size
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8192&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;row&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;aside class=&#34;thought&#34;&gt;
&lt;h3&gt;Shared cache vs disk?&lt;/h3&gt;
&lt;p&gt;Postgres maintains a cache in memory, the &amp;ldquo;shared buffer cache&amp;rdquo;, where it stores data that it has fetched from disk for faster retrieval later. Fetches from this store are massively faster than fetches from disk when the cache is &amp;ldquo;missed&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Postgres doesn&amp;rsquo;t just fetch data from either the cache or disk that &lt;em&gt;it will return&lt;/em&gt;, it fetches data from both stores that it needs &lt;em&gt;to determine the rows that it will return&lt;/em&gt;. For an unoptimized query it is possible for postgres to fetch a significant amount of data that it never sends to the client. Minimising the data you fetch from disk to determine your eventual result set that is then discarded is key to optimizing the IO usage of your queries.&lt;/p&gt;
&lt;p&gt;You can find the &lt;a href=&#34;https://www.postgresql.org/docs/current/runtime-config-resource.html&#34;&gt;docs for the shared_buffers setting here&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Taking this block size value and going back to our Buffers report:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Buffers: shared hit=1166 read=3117
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see here that &lt;strong&gt;1166 blocks (9,551,872 bytes) were provided by the shared cache&lt;/strong&gt;, but &lt;strong&gt;3117 blocks (25,534,464 bytes) had to be read from disk&lt;/strong&gt;. This was the data reported from the location I marked with &lt;code&gt;(0)&lt;/code&gt;, but there are other locations too, marked with &lt;code&gt;(1)&lt;/code&gt;, &lt;code&gt;(2)&lt;/code&gt; and &lt;code&gt;(3)&lt;/code&gt;. The &lt;code&gt;EXPLAIN&lt;/code&gt; command breaks down buffer usage by section, and the report is cumulative, so the buffer usage reported in sections &lt;code&gt;(2)&lt;/code&gt; and &lt;code&gt;(3)&lt;/code&gt; when added together equal the buffer usage reported at the parent node in section &lt;code&gt;(1)&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;p&gt;The breakdown by section means that you can see where the buffer usage is highest and target your optimization in that area. For instance in the example query you can see that more than 95% of the buffer usage happens in section &lt;code&gt;(3)&lt;/code&gt;, the &lt;code&gt;Index Scan using index_events_on_activity_logs_id&lt;/code&gt; and so this area would be a good place to start investigating optimizations.&lt;/p&gt;
&lt;aside class=&#34;thought&#34;&gt;
&lt;h3&gt;Why does it matter if we go to disk instead of the shared cache in memory?&lt;/h3&gt;
Disk (SSD) read speeds are substantially slower than reads from memory, in the region of 450 MB/s for an SSD compared to around 13,000 MB/s for memory (varying depending on the specific hardware). The &#34;Latency numbers every programmer should know&#34; table, originally by &lt;a href=&#34;http://norvig.com/21-days.html#answers&#34;&gt;Peter Norvig&lt;/a&gt; shows the difference well.
&lt;pre&gt;&lt;code&gt;L1 cache reference ......................... 0.5 ns
Branch mispredict ............................ 5 ns
L2 cache reference ........................... 7 ns
Mutex lock/unlock ........................... 25 ns
Main memory reference ...................... 100 ns
Compress 1K bytes with Zippy ............. 3,000 ns  =   3 µs
Send 2K bytes over 1 Gbps network ....... 20,000 ns  =  20 µs
SSD random read ........................ 150,000 ns  = 150 µs
Read 1 MB sequentially from memory ..... 250,000 ns  = 250 µs
Round trip within same datacenter ...... 500,000 ns  = 0.5 ms
Read 1 MB sequentially from SSD ...... 1,000,000 ns  =   1 ms (Assuming ~1GB/sec SSD)
Disk seek ........................... 10,000,000 ns  =  10 ms
Read 1 MB sequentially from disk .... 20,000,000 ns  =  20 ms
Send packet CA-&amp;gt;Netherlands-&amp;gt;CA .... 150,000,000 ns  = 150 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;/aside&gt;
&lt;p&gt;Before we get into what this buffers data in the explain output is useful for, let&amp;rsquo;s run the explain again with the same parameters to see what happens:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;EXPLAIN&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;ANALYSE&lt;/span&gt;, BUFFERS)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events.&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;INNER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; activity_logs &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; events.activity_logs_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; activity_logs.id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	activity_logs.user_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;83463&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.date &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-04&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.duration &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; events.exception_id &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	date &lt;span style=&#34;color:#66d9ef&#34;&gt;ASC&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; NULLS &lt;span style=&#34;color:#66d9ef&#34;&gt;LAST&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Sort  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;37&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;150&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;151&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Sort &lt;span style=&#34;color:#66d9ef&#34;&gt;Key&lt;/span&gt;: events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; NULLS &lt;span style=&#34;color:#66d9ef&#34;&gt;LAST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Sort &lt;span style=&#34;color:#66d9ef&#34;&gt;Method&lt;/span&gt;: quicksort  Memory: &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3577&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  Nested Loop  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;10157&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;35&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;145&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;145&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3577&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; index_activity_logs_on_user_id_and_event_start_and_event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt; activity_logs  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;56&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;325&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;82&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;020&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;350&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;315&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						&lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Cond: (user_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;83463&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;45&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; index_events_on_activity_logs_id &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt; events  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;57&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;119&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;89&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;018&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;018&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;315&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						&lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Cond: (activity_logs_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; activity_logs.id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Filter: ((((event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (duration &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::double &lt;span style=&#34;color:#66d9ef&#34;&gt;precision&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; (exception_id &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (date &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-04&amp;#39;&lt;/span&gt;::date))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						&lt;span style=&#34;color:#66d9ef&#34;&gt;Rows&lt;/span&gt; Removed &lt;span style=&#34;color:#66d9ef&#34;&gt;by&lt;/span&gt; Filter: &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3532&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;148&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Planning Time: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;445&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Execution Time: &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;198&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What you can see here from the buffer data is that Postgres no-longer has to go to disk. The data that was read in the previous query is now in the shared cache so we&amp;rsquo;re fetching all our data from memory, there is no &lt;code&gt;read=nnnn&lt;/code&gt; reported:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Buffers: shared hit=3577
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This results in a much faster query time, the original query took 2291ms and the cached one 6ms ⚡️. Unfortunately even though this query was much faster the second time round we don&amp;rsquo;t always have the luxury of running queries that are cached so we often need to optimize for the cold cache situation, plus if we can reduce the buffers usage of the query we can make it even faster and less resource intensive still, plus if we can trim the data pulled from the shared cache down too that will also help with performance.&lt;/p&gt;
&lt;p&gt;So, what can we use this information for? The query I&amp;rsquo;m using in the example is similar to one I optimized for a client that was the highest IO usage of all queries on their production server at nearly 16% if all IO used.&lt;/p&gt;
&lt;p&gt;When we&amp;rsquo;re trying to improve the performance of this query we can make it faster, and that would be great by itself and is often the main goal of a performance optimization, but we really want to actually &lt;strong&gt;verify that any changes we make have reduced the IO&lt;/strong&gt; which is the larger problem here; we really want to stick to the performance optimization mantra of &amp;ldquo;measure, change, measure&amp;rdquo;. &lt;strong&gt;With the buffers data we can see what difference we&amp;rsquo;re making&lt;/strong&gt;, if any, to the performance of the query as we change it. Here&amp;rsquo;s the same query on a cold cache but with an optimization:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;EXPLAIN&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;ANALYSE&lt;/span&gt;, BUFFERS)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events.&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;INNER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;JOIN&lt;/span&gt; activity_logs &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; events.activity_logs_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; activity_logs.id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	activity_logs.user_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;348927&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.date &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-04&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#3c3d38&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; activity_logs.event_start &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-10&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; events.duration &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; events.exception_id &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	date &lt;span style=&#34;color:#66d9ef&#34;&gt;ASC&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; NULLS &lt;span style=&#34;color:#66d9ef&#34;&gt;LAST&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Sort  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1491&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;66&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;1491&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;67&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;855&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;856&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Sort &lt;span style=&#34;color:#66d9ef&#34;&gt;Key&lt;/span&gt;: events.event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt; NULLS &lt;span style=&#34;color:#66d9ef&#34;&gt;LAST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Sort &lt;span style=&#34;color:#66d9ef&#34;&gt;Method&lt;/span&gt;: quicksort  Memory: &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  Nested Loop  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;1491&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;65&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;850&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;851&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; index_activity_logs_on_user_id_and_event_start_and_event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt; activity_logs  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;56&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;51&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;70&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;) (actual time&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;850&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;850&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; loops&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Cond: ((user_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;348927&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (event_start &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-10&amp;#39;&lt;/span&gt;::date))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;read&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Scan &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; index_events_on_activity_logs_id &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt; events  (cost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;57&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;119&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; width&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;166&lt;/span&gt;) (never executed)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#66d9ef&#34;&gt;Index&lt;/span&gt; Cond: (activity_logs_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; activity_logs.id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              Filter: ((((event_start &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (event_end &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (duration &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0&amp;#39;&lt;/span&gt;::double &lt;span style=&#34;color:#66d9ef&#34;&gt;precision&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; (exception_id &lt;span style=&#34;color:#66d9ef&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;)) &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (date &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2022-12-04&amp;#39;&lt;/span&gt;::date))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Planning:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Buffers: shared hit&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;148&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Planning Time: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;427&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Execution Time: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;.&lt;span style=&#34;color:#ae81ff&#34;&gt;897&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The specific optimization isn&amp;rsquo;t relevant here (it&amp;rsquo;s the addition of the condition &lt;code&gt;AND activity_logs.event_start &amp;gt; &#39;2022-12-10&#39;&lt;/code&gt; which I highlighted), I&amp;rsquo;ll talk about that in another article, but what you can see if you compare to the earlier uncached query plan is that the &amp;ldquo;Execution Time&amp;rdquo; is far smaller at 1.9ms, down from 2290ms, but also &lt;strong&gt;the amount of data fetched from disk (the &amp;ldquo;read&amp;rdquo; buffers) is far smaller too&lt;/strong&gt; at 2 blocks, or 16,384 bytes, down from 25,534,464 bytes before.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Buffers: shared hit=1166 read=3117
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;vs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Buffers: shared hit=2 read=2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;rsquo;s a reduction of over 24 MB, a huge IO amount of IO to trim from the query! With this data we have a pretty good idea that we&amp;rsquo;ve made a significant difference to the IO problem.&lt;/p&gt;
&lt;aside class=&#34;thought&#34;&gt;
&lt;h3&gt;The changing user_id and statistical comparison&lt;/h3&gt;
&lt;p&gt;You might have noticed that the ID of the &lt;code&gt;activity_logs.user_id&lt;/code&gt; changed in that last query, and be wondering if the different data returned by the query will alter it&#39;s performance characteristics, and that would be correct. Ideally it would be possible to flush the shared cache between tests to make the test fair, but that&#39;s hard to do with Postgres. To do so you would need to shut down the Postgres server process, dump linux&#39;s cache, and restart Postgres. That&#39;s fairly cumbersome so instead what I do is to run the original and changed queries multiple times using different IDs to get a statistical comparison of the effect the change has.
&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;At scale IO can be a significant performance bottleneck for databases and optimizing problem queries that cause large amounts of IO can yield significant benefits. Adding the &lt;code&gt;BUFFERS&lt;/code&gt; option when using &lt;code&gt;EXPLAIN ANALYSE&lt;/code&gt; can give you a great way to identify problem areas of a query, and to verify when you&amp;rsquo;re done that you&amp;rsquo;ve actually solved the issue.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve found this interesting you might be interested in second part of this article, &lt;a href=&#34;https://willj.net/posts/measuring-io-timing-for-postgres-explain-analyse&#34;&gt;Measuring IO timings when using EXPLAIN ANALYSE in Postgres&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Converting a wordpress.com dump to Hugo, including images</title>
      <link>https://willj.net/posts/converting-a-wordpress.com_dump_to_hugo/</link>
      <pubDate>Tue, 12 Sep 2023 13:30:00 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/converting-a-wordpress.com_dump_to_hugo/</guid>
      <description>&lt;p&gt;There are a few &lt;a href=&#34;https://gohugo.io/tools/migrations/#wordpress&#34;&gt;&amp;ldquo;official&amp;rdquo; options for migrating wordpress content to Hugo&lt;/a&gt;, but they are all either cumbersome (requiring installing wordpress in docker) or don&amp;rsquo;t handle images. I didn&amp;rsquo;t want to spend too much time on this and definitely wanted images to be converted so wrote a quick program to handle the conversion for me.&lt;/p&gt;
&lt;p&gt;In the end &lt;a href=&#34;https://github.com/wjessop/wordpress_to_hugo&#34;&gt;I created a somewhat rough, but functional program to do the job&lt;/a&gt; and it was successful.&lt;/p&gt;
&lt;p&gt;The requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extracts tags where there are any on the original post and adds them to the front Hugo matter&lt;/li&gt;
&lt;li&gt;Maintains the original post date&lt;/li&gt;
&lt;li&gt;Converts the HTML to Markdown&lt;/li&gt;
&lt;li&gt;Maintains the directory structure, with images copied to the directory that the post&amp;rsquo;s index.md is in:
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-thing&#34; data-lang=&#34;thing&#34;&gt;basedir/
  content/
    posts/
      Some-post-title/
        index.md
        images/
          post-image-1.jpg
          post-image-2.png
     A-different-post-title/
      index.md
      images/
        post-image-for-this-other-arcicle.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are some caveats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Posts require some fixup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a little bit of tweaking that I&amp;rsquo;ve had to do to Hugo front matter or the posts, but the program got me mostly all the way. These things could likely be fixed in the code and it would be worth doing so if I was going to run the program more than once, but I&amp;rsquo;m not so it was faster to fix things up manually.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Doesn&amp;rsquo;t write the summary&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I had to write this manually, but I was only dealing with 10s of posts. If you want to use this then you might want to add something to generate a summary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Doesn&amp;rsquo;t always get the image URLs right in the markdown (but it&amp;rsquo;s easily fixable)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The code left a few images URLs in the posts pointing to the old wordpress site. It still copied over the images so it was a really simple find and replace to fix these up.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Doesn&amp;rsquo;t do any error checking, just panics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It didn&amp;rsquo;t error so I didn&amp;rsquo;t put in the time to handle errors as it was a one-off program, it worked for me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Skips image only posts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This was delberate, but you might want to add that feature.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyway, the code got me 90% of the way to where I wanted the posts to get so worked well for what I wanted it to do and I&amp;rsquo;d call it a success. &lt;a href=&#34;https://github.com/wjessop/wordpress_to_hugo&#34;&gt;I&amp;rsquo;ve put the code up on Github&lt;/a&gt;, I likely won&amp;rsquo;t need to run this code again, but if it&amp;rsquo;s useful to you please feel free to submit PRs.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Reverting Firefox&#39;s recent URL bar suggestion order change</title>
      <link>https://willj.net/posts/revert-firefox-url-bar-suggestion-order-change/</link>
      <pubDate>Mon, 11 Sep 2023 17:27:00 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/revert-firefox-url-bar-suggestion-order-change/</guid>
      <description>&lt;p&gt;A recent update to Firefox changed the order of suggestions when you started typing in the URL bar (or &amp;ldquo;address bar&amp;rdquo;). It used to be that you&amp;rsquo;d get recently visited URLs first but the change caused search suggestions to appear first. I almost always navigate to sites I know by typing the first few letters of the domain name and almost never used the search suggestions so this change cause consternation.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/revert-firefox-url-bar-suggestion-order-change/images/Before.png&#34;
    alt=&#34;A firefox URL bar suggestions dropdown showing suggested searches before recently visited sites&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The URL bar suggestions after Firefox &amp;#34;Improved&amp;#34; the experience in a recent update and changed the suggestions order&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Fearing for the longevity of my down arrow key caused the wear of all the extra pressing to get down to the recently visited URLs section I searched for a solution. It turns out that you can change the order of the suggestions in the config. To do so:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open a new Firefox tab&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;about:config&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Accept any warnings (yolo)&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;browser.urlbar.showSearchSuggestionsFirst&lt;/code&gt; into the search field&lt;/li&gt;
&lt;li&gt;Toggle the value&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You shouldn&amp;rsquo;t need to restart Firefox for the change to take effect, and should now have your URL history back where it was before the search suggestions.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/revert-firefox-url-bar-suggestion-order-change/images/After.png&#34;
    alt=&#34;A firefox URL bar with recently visited sites before search suggestions&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;URL bar suggestion order, now fixed&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Fitting two hard drives and an SSD in a Dell OptiPlex 7010 SFF</title>
      <link>https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/</link>
      <pubDate>Sun, 28 May 2023 00:00:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/</guid>
      <description>&lt;hr&gt;
&lt;h1 id=&#34;update&#34;&gt;Update!&lt;/h1&gt;
&lt;p&gt;It turns out that this is a Dell OptiPlex 7010 SFF, not a USFF (as advertised by the eBay seller)!&lt;/p&gt;
&lt;hr&gt;
&lt;figure class=&#34;right&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/DELL-Optiplex-7010-SFF.jpg&#34;
    alt=&#34;A Dell OptiPlex 7010 Ultra Small Form Factor&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;A Dell OptiPlex 7010 SFF&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I recently bought a &lt;a href=&#34;https://www.dell.com/support/kbdoc/en-uk/000212008/dell-optiplex-small-form-factor-7010-system-guide&#34;&gt;Dell OptiPlex 7010 Small Form Factor&lt;/a&gt; PC from eBay. I was Intending on squeezing two of the spare Seagate Barracuda 4TB 3.5&amp;quot; hard drives I have in it with an SSD boot disk and installing &lt;a href=&#34;https://www.truenas.com/&#34;&gt;TrueNAS&lt;/a&gt; to use it as a file store. It&amp;rsquo;s a small, quiet machine and should be ideal, but when I was doing my research into what I should buy I think I got the SFF (Ultra Small Form Factor) confused with another Dell OptiPlex machine and it turns out that the SFF model I got can only officially fit a single 2.5&amp;quot; SSD in it, and no 3.5&amp;quot; drives at all. Whoops.&lt;/p&gt;
&lt;p&gt;Opening up the machine it turns out that there was actually a 3.5&amp;quot; drive bay and the eBay seller used a tiny amount of hot glue to just glue a 2.5&amp;quot; SSD into the bay rather than using an adapter. Quality. This didn&amp;rsquo;t help much though, there was still no way of fitting the number of drives I wanted in the machine as it came. Anyway, after removing the SSD, the official Dell drive mounts and the slim CDRW drive I took a look at the situation and figured I could probably rescue this with a bit of 3d printing. Any day that requires you to solve a problem with a bit of 3d printing is generally a good day.&lt;/p&gt;
&lt;h2 id=&#34;caveat&#34;&gt;Caveat!&lt;/h2&gt;
&lt;p&gt;This works for my Seagate Barracuda 4TB drives. They&amp;rsquo;re slightly thinner than some of the other drives I&amp;rsquo;ve got, if yours are thicker then it might work for yoiu or it might not.&lt;/p&gt;
&lt;h2 id=&#34;risers-of-the-machine&#34;&gt;Risers of the Machine&lt;/h2&gt;
&lt;figure class=&#34;left&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/Dell-Optiplex-7010-SFF-inside.jpg&#34;
    alt=&#34;View inside a Dell OptiPlex 7010 Ultra Small Form Factor&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;View inside a Dell OptiPlex 7010 SFF, there isn&amp;#39;t much room&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;right&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/Dell-OptiPlex-7010-motherboard.jpg&#34;
    alt=&#34;A Dell OptiPlex 7010 Ultra Small Form Factor motherboard&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The motherboard. Red circles are candidates for risers, the turquoise square is where the CPU heat sink and fan are&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Once the existing mounts had been removed I could see that there were four screws holding the motherboard in place, and an existing riser, all of which could be re-purposed as places to screw a riser which would allow me to mount drives suspended over the RAM. See the image where I&amp;rsquo;ve marked the locations of these holes with a red circle. The turquoise square is about where the CPU heatsink and fan are, but the heatsink is low profile and draws the heat towards the back of the machine closer to the IO ports where the fan is.&lt;/p&gt;
&lt;h2 id=&#34;the-curse-of-the-imperial-menace&#34;&gt;The Curse of the Imperial Menace!&lt;/h2&gt;
&lt;p&gt;Metric is the best and only measurement system anyone should use, but unfortunately PC manufacturers seem to have settled on imperial for at least the bolt hole sizes I need to use which are &lt;a href=&#34;https://en.wikipedia.org/wiki/Unified_Thread_Standard&#34;&gt;6-32 UNC&lt;/a&gt;. The risers I need to incorporate into this design are fairly long too at nearly 40mm. That&amp;rsquo;s about M3.5 * 40mm in metric, but I couldn&amp;rsquo;t find any M3.5 risers of the right height, and I can buy 6-32 UNC bolts on eBay easily enough so I bought some of those. You can probably use M3.5 as a substitute.&lt;/p&gt;
&lt;h2 id=&#34;to-fusion360&#34;&gt;To Fusion360!&lt;/h2&gt;
&lt;p&gt;These days my 3d designing tool of choice is Fusion 360 so I opened it up and set to work. Much cursing, and a fair few scrapped prototypes later I came up with this:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/Fusion%20360%20design.png&#34;
    alt=&#34;A mount for two 3.5 inch and one 2.5 inch hard drive&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;3d design isn&amp;#39;t my day job&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s definitely not going to win any awards for beautiful design, and it&amp;rsquo;s got some problems, but it works. I could certainly have improved the design further, but I was running out of patience with 3d printing prototypes I had to throw away, and time on my Fusion 360 trial (damn you Autodesk!). Anyway, it&amp;rsquo;s ugly, it&amp;rsquo;s flawed, but it works.&lt;/p&gt;
&lt;h2 id=&#34;the-finished-mount-in-action&#34;&gt;The finished mount in action&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the first part of the install showing the &amp;ldquo;base&amp;rdquo; of the mount. The SSD is slung underneath with M3 bolts * 12mm, because that was what I had. I should have made the recess for the bolt heads a bit deeper so the bolt heads were further away from the underside of the bottom hard drive, but though it&amp;rsquo;s tight it doesn&amp;rsquo;t touch so I&amp;rsquo;m leaving it.&lt;/p&gt;
&lt;p&gt;There is about 5mm clearance between the bottom of the mount and the RAM, and enough clearance between the SSD and the CPU cooler for wires to pass comfortably. The SSD could be mounted about 5mm higher, closer to the bottom of the first hard drive, but I only had 12mm bolts in M3.5 and so had to print spacers.&lt;/p&gt;
&lt;p&gt;There are captive nuts on the top-left of this image underneath the base, nearest the front of the case. These were exactly the right size for the nuts I was using, which meant that the nuts stayed in right up until I used any force at all on them like when I was trying to screw a bolt into them. This was infuriating so I epoxied the nuts in place. If I was to do another version of this I&amp;rsquo;d make the nut traps tighter so the nuts could be safely held in place with a press fit.&lt;/p&gt;
&lt;p&gt;The two bolts you can see with two nuts on them used as spacers, these are a flaw in the design. In order to prevent the 50mm bolts I was using from bottoming out I could have used shorter bolts and printed recesses, but I didn&amp;rsquo;t want to buy more imperial bolts I was never going to use again. I could have printed spacers, but the nuts worked and they were there. In the end I had to remove one of the nuts from the bottom-left most bolt so it didn&amp;rsquo;t foul the hard drive, but it didn&amp;rsquo;t bottom out even then so it worked out.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/IMG_5160.jpeg&#34;
    alt=&#34;A custom 3d printed HD mount inside the Dell OptiPlex case&#34;&gt;
&lt;/figure&gt;

&lt;p&gt;Here you can see the 3.5&amp;quot; hard drives in place. There is a gap between the two drives to allow for air flow.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/IMG_5161.jpeg&#34;
    alt=&#34;2 hard drives mounted on the fully assembled custom mount&#34;&gt;
&lt;/figure&gt;

&lt;p&gt;Here you can see how tight it is near the case fan, the tolerances in this design are pretty tight. I couldn&amp;rsquo;t shift the hard drives further away from the front of the case/the case fan because the latch in the removable panel on the case prevents them from moving backwards in the case.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/IMG_5164.jpeg&#34;
    alt=&#34;the mounted hard drives very close to the front of the case and the case fan&#34;&gt;
&lt;/figure&gt;

&lt;p&gt;The front of the case looking in through the old CDRW slot. It doesn&amp;rsquo;t look like it but there is a mm or two clearance between the top of the top hard drive and the case when the lid is on.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/IMG_5162.jpeg&#34;
    alt=&#34;Hard drives seen through the front of the PC case&#34;&gt;
&lt;/figure&gt;

&lt;p&gt;The same view but with the lit fitted.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/IMG_5165.jpeg&#34;&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;parts-list&#34;&gt;Parts list&lt;/h2&gt;
&lt;p&gt;If you want to make this mount exactly as I did then you will need these parts, or metric equivalent. Just bear in mind that it could be improved, so if you&amp;rsquo;ve got access to a 3d design program and the willingness it could be better. Let me know if you release an improved model and I&amp;rsquo;ll link it here.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;4 x 6-32 UNC * 50mm bolts&lt;/li&gt;
&lt;li&gt;5 x 6-32 UNC nuts (or 2 x if you print out spacers for the risers, see first image and description in &amp;ldquo;The finished mount in action&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;4 x M3 * 12mm flat head bolts for the SSD&lt;/li&gt;
&lt;li&gt;10 x standard HD mounting screws (8 for the HDs, 2 for the base)&lt;/li&gt;
&lt;li&gt;SATA cables&lt;/li&gt;
&lt;li&gt;A SATA power splitter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The SSD bolts looks like this:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fitting-two-hard-drives-and-an-ssd-in-a-dell-optiplex-7010-usff/images/IMG_5238.jpeg&#34;&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;printing-instructions&#34;&gt;Printing instructions&lt;/h2&gt;
&lt;p&gt;The design is printed in parts. Print one each of all parts you see in the image above, except you&amp;rsquo;ll need four of the risers (the long thing sticking down on the bottom left of the image) and four of the SSD mounting spacers if you&amp;rsquo;re using the same m3 bolts as me. Adjust or omit these if you have different length M3 bolts.&lt;/p&gt;
&lt;p&gt;Any 3d printer should work, but all this was printed on a Prusa i3 MK3S, if you&amp;rsquo;re looking for your own 3d printer then the &lt;a href=&#34;https://www.prusa3d.com/category/original-prusa-mk4/&#34;&gt;Prusa i3 MK4&lt;/a&gt; would be a great option.&lt;/p&gt;
&lt;h2 id=&#34;things-id-do-differently&#34;&gt;Things I&amp;rsquo;d do differently&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The HD Screws aren&amp;rsquo;t really long enough for going through a nut and two layers of 3d print, so where I&amp;rsquo;ve used them to connect the base of the mount the print is a little thin to allow for all the thread to pass through and bite into the thread in the nut. I could have used different screws/bolts or could likely have done this without any screws at all with an interlocking design, but this works and I don&amp;rsquo;t want to re-design it.&lt;/li&gt;
&lt;li&gt;Make the SSD mounting bolt head recesses very slightly deeper.&lt;/li&gt;
&lt;li&gt;Made the nut traps tighter, the nuts were loose which made installation a pain.&lt;/li&gt;
&lt;li&gt;Re-designed to use less 3d printing and to take advantage of the HDs inherant stiffness. The HDs are made of metal, and I didn&amp;rsquo;t need anywhere near as much 3d printed structure to keep them in place, I could have relied on the inherant stiffness of the drives more.&lt;/li&gt;
&lt;li&gt;Made the risers tighter so they didn&amp;rsquo;t fall off the long bolts on installation.&lt;/li&gt;
&lt;li&gt;Made the base installable first then the HDs bolt onto that, as it stands there&amp;rsquo;s a fiddly installation process and you have to remove pretty much the whole thing to change a drive.&lt;/li&gt;
&lt;li&gt;The riser closest to the power button interferes with the HD if you offset it from the base the correct amount, I&amp;rsquo;d re-design that (see first picture and description under &amp;ldquo;The finished mount in action&amp;rdquo;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;things-to-test-later&#34;&gt;Things to test later&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve fully assembled the mount, powered it on, installed TrueNAS and started using it as a file store, so it works. A couple of things I&amp;rsquo;d like to test at some point but haven&amp;rsquo;t got round to:&lt;/p&gt;
&lt;h3 id=&#34;heat&#34;&gt;Heat&lt;/h3&gt;
&lt;p&gt;Adding more things into the case means less airflow. I think there&amp;rsquo;s still enough (below the mount, round the side near the case fan, between the hard drives) that it&amp;rsquo;s not going to overheat, but I&amp;rsquo;ll be monitoring the heat using the TrueNAS UI.&lt;/p&gt;
&lt;h2 id=&#34;power-usage&#34;&gt;Power usage&lt;/h2&gt;
&lt;p&gt;The PSU is 64W I think, but seems to be fine driving two mirrored 5400 RPM drives and an SSD. I left my power monitor on my boat though so will test when I get the chance.&lt;/p&gt;
&lt;h2 id=&#34;downloads&#34;&gt;Downloads&lt;/h2&gt;
&lt;p&gt;The Fusion 360 design file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;Dell%20Optiplex%207010%20SFF%20HD%20Mount.f3d&#34;&gt;Dell Optiplex 7010 SFF HD Mount.f3d&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;STL:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;stl/Base.stl&#34;&gt;Base&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;stl/Front%20top.stl&#34;&gt;Front top&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;stl/Back%20top.stl&#34;&gt;Back top&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;stl/Riser.stl&#34;&gt;Riser&lt;/a&gt; (print x 4)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;stl/SSD%20Offset.stl&#34;&gt;SSD Offset&lt;/a&gt; (print x 4)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve said it before, but it&amp;rsquo;s worth repeating. This mount works just fine, the drives are well fixed in place, the cables stay in, the case lid closes. However, designing stuff isn&amp;rsquo;t my day job and this design has a number of issues that if someone with more time and who is better at 3d design wanted to build on then it could be greatly improved. If I were to print a new version of this I&amp;rsquo;d probably alter the design quite a lot.&lt;/p&gt;
&lt;p&gt;All that said, if you want to print this, and have the parts, then I don&amp;rsquo;t see any reason why it shouldn&amp;rsquo;t also work for you, it&amp;rsquo;s working for me.&lt;/p&gt;
&lt;p&gt;Let me know if you use this or improve it! Contact details on &lt;a href=&#34;https://willj.net/&#34;&gt;the homepage&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Running a specific knapsack test set locally</title>
      <link>https://willj.net/posts/running-a-specific-knapsack-test-set-locally/</link>
      <pubDate>Wed, 26 Apr 2023 15:00:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/running-a-specific-knapsack-test-set-locally/</guid>
      <description>&lt;p&gt;Sometimes you have a test order issue CI that you want to debug locally, and to do that you need to only run the tests that knapsack runs in the relevant shard, in the right order. Here&amp;rsquo;s how to do that!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Grab &lt;code&gt;CI_NODE_TOTAL&lt;/code&gt; and &lt;code&gt;CI_NODE_INDEX&lt;/code&gt; from the test output, it&amp;rsquo;s likely near the top:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;images/ci-node-data.png#full&#34; alt=&#34;Getting the CI node data from CI output&#34;&gt;&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Grab the seed value, it&amp;rsquo;s probably going to be near the bottom of the output:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;images/seed.png#full&#34; alt=&#34;Getting the seed value from CI output&#34;&gt;&lt;/p&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;Run the command with the interpolated values you got above&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; $ RAILS_ENV=test CI=true CI_NODE_TOTAL=16 CI_NODE_INDEX=4 bundle exec rake &amp;quot;knapsack:rspec[--seed 43092 --format documentation]&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might also want to add &lt;code&gt;--fail-fast&lt;/code&gt; to the options to cut short the test suite when you hit your error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; $ RAILS_ENV=test CI=true CI_NODE_TOTAL=16 CI_NODE_INDEX=4 bundle exec rake &amp;quot;knapsack:rspec[--seed 43092 --format documentation --fail-fast]&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can even &lt;code&gt;rspec bisect&lt;/code&gt; across this set of tests:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; $ OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES RAILS_ENV=test CI=true CI_NODE_TOTAL=16 CI_NODE_INDEX=13 bundle exec rake &amp;quot;knapsack:rspec[--seed 16837 --bisect]&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I added &lt;code&gt;OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES&lt;/code&gt; as there &lt;a href=&#34;https://stackoverflow.com/questions/52671926/rails-may-have-been-in-progress-in-another-thread-when-fork-was-called&#34;&gt;is bug/issue with Ruby&lt;/a&gt; on OS X, you should be able to remove that environment variable on Linux.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
      
      <item>
      <title>Will&#39;s YouTube sailing channel recommendations</title>
      <link>https://willj.net/posts/youtube-sailing-channel-recommendations/</link>
      <pubDate>Thu, 15 Sep 2022 00:00:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/youtube-sailing-channel-recommendations/</guid>
      <description>&lt;p&gt;I started watching YouTube sailing videos in about 2014 when I discovered &lt;a href=&#34;https://www.youtube.com/channel/UCZdQjaSoLjIzFnWsDQOv4ww&#34;&gt;Sailing la Vagabonde&lt;/a&gt;. I&amp;rsquo;d never really considered that sailing was something I could be interested in, I didn&amp;rsquo;t know anything about it at all. I remember being on holiday with my wife in Greece a few times and seeing sailing yachts moored up in the harbours, and I think there was a curiosity about the boats, and the people eating what I probably assumed were fancy lunches on them. I must have seen yachts in the sea, or in harbours or marinas, but I don&amp;rsquo;t really remember. They were just part of the view, not something to be interacted with. A different world. Billionaire bosses and boat shoes.&lt;/p&gt;
&lt;p&gt;Anyway, I ignored sailing, and sailing ignored me, until one day a cooking show I watched linked to la Vagabonde. I was suddenly given a peek behind the curtain, a view into a previously unknown world and I was pretty curious, so I kept watching. These people seemed… normal, approachable. I started to consume the la Vagabonde back catalogue, and was curious if there were more people making these videos. A quick google later and I&amp;rsquo;d found Delos, and after a couple of tries (their early videos were hard to get through) I started working my way through their back catalogue too, and so started my interest in sailing that has lasted 8 years, and has now seen us buy &lt;a href=&#34;https://sailingsilvergirl.com&#34;&gt;our own boat&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Over those years I&amp;rsquo;ve gathered a number of YouTube subscriptions and figured I&amp;rsquo;d share them here, save people having to dig through the less great content out there to find some gems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/c/svdelos&#34;&gt;SV Delos&lt;/a&gt; - Try to push through the earlier videos, this one of the most widely respected sailing channels out there, but the early videos don&amp;rsquo;t do them justice.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/@SailLife&#34;&gt;Sail Life&lt;/a&gt; - First several years are a re-fit (which was very well filmed and I loved), but they&amp;rsquo;re sailing now.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCLYd5EnTTwUKhouIkHoqzMw&#34;&gt;Ran Sailing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCXbWsGV_cjG3gOsSnNJPVlg&#34;&gt;Sailing Uma&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UC-e4fYEUg2tVQ0NGL9oD1RQ&#34;&gt;Sailing Millennial Falcon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCUH6fLsV6J7WKEmf7vJKfAw&#34;&gt;Erik Aanderaa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCkExLY1E6CE-GPsMCdSjmxQ&#34;&gt;Sailing Yacht Florence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCF45qzioJ_0FVdZVG2NJTWg&#34;&gt;Sailing Project Atticus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCS6qLhh5YBeL42HRMh3dc1A&#34;&gt;Christian Williams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCBczX15IcXx0OqhqwlUtJjw&#34;&gt;Sailing cos I love it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCTmJcC_Yw3IL7Bvtf_7nTLw&#34;&gt;How to Sail Oceans&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/c/SailingSweetRuca&#34;&gt;Sailing Sweet Ruca&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCGFbz7qMXCm28EPCkZWSMKg&#34;&gt;Calico Skies Sailing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/c/SailingMagicCarpet&#34;&gt;Magic Carpet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/c/parlayrevival&#34;&gt;Parlay Revival&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCZdQjaSoLjIzFnWsDQOv4ww&#34;&gt;Sailing La Vagabonde&lt;/a&gt; - I don&amp;rsquo;t watch them as much anymore, they do a lot less stuff I&amp;rsquo;m interested in.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/user/gonewiththewynns&#34;&gt;Gone with the Wynns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCRqsOR0Y2zru-jXSzLcMcxg&#34;&gt;Sailing Soulianis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCE4vct4tqxSuG4JH6vMVZSA&#34;&gt;Sam Holmes Sailing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCvJGfEEg7R04-ifkg_FFnaw&#34;&gt;MJ Sailing&lt;/a&gt; - Currently doing a rather dry, no pun untended, boat build, but see old videos.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UCT9U1fPkHj0mJjC4LWGH26g&#34;&gt;Sailing Kittiwake&lt;/a&gt; - They seem to have stopped posting now&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/channel/UC9rRsBE2nFbnUSjtmv6Jq6w&#34;&gt;Sailing Ruby Rose&lt;/a&gt; - Currently rather dry Catamaran videos, but the earlier stuff was good.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these are pure sailing, some more &amp;ldquo;lifestyle&amp;rdquo; sailing. I like each for different reasons. Some I tolerate and only watch when I&amp;rsquo;ve run out of other stuff, but see what you like. Bear in mind not everything these people do is a good idea, but it&amp;rsquo;s a pretty easy way of immersing yourself in the scene without any outlay.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Full-height Github &#34;checks&#34; box in Firefox</title>
      <link>https://willj.net/posts/full-height-github-checks-box-in-firefox/</link>
      <pubDate>Tue, 16 Aug 2022 12:00:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/full-height-github-checks-box-in-firefox/</guid>
      <description>&lt;p&gt;The scrolling checks box on Github &lt;strong&gt;really&lt;/strong&gt; irritates me. Follow these instructions to make it full height on Firefox.&lt;/p&gt;
&lt;h2 id=&#34;1-take-this-css&#34;&gt;1. Take this CSS:&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;branch-action-item&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;merge-status-list-wrapper&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;merge-status-list&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;branch-action-item&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;merge-status-list&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;max-height&lt;/span&gt;: fit-content &lt;span style=&#34;color:#75715e&#34;&gt;!important&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;2-tell-firefox-to-use-the-new-css&#34;&gt;2. Tell Firefox to use the new CSS&lt;/h2&gt;
&lt;p&gt;Follow the guide &lt;a href=&#34;https://davidwalsh.name/firefox-user-stylesheet&#34;&gt;here&lt;/a&gt; for adding it to the custom CSS. And done, full height checks box!&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/full-height-github-checks-box-in-firefox/images/full-height-github-checks-box.png&#34;
    alt=&#34;Notifications in action in Apple Mail&#34;&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Effective Github Notifications</title>
      <link>https://willj.net/posts/effective-github-notifications/</link>
      <pubDate>Tue, 16 Aug 2022 00:00:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/effective-github-notifications/</guid>
      <description>&lt;p&gt;Github notifications can be overwhelming, but with effective email filtering they can be turned from an encumbrance to being highly valuable. Here&amp;rsquo;s some filters to get you started (in Mail.app on a mac) to make them more useful.&lt;/p&gt;
&lt;p&gt;Luckily Github provides us with the tools to make this filtering relatively easy. All email notifications sent from Github are automatically CCed to a Github email address that describes what they are, and this is the hook we use to create our filters.&lt;/p&gt;
&lt;p&gt;All email addresses here are @github.com, even though in some examples they are hidden, and these rules can be added to the GMail web UI too if needed.&lt;/p&gt;
&lt;h2 id=&#34;flag-high-priority-notifications&#34;&gt;Flag high priority notifications&lt;/h2&gt;
&lt;p&gt;Mark &lt;strong&gt;assignments&lt;/strong&gt;, &lt;strong&gt;review requests&lt;/strong&gt;, &lt;strong&gt;mentions&lt;/strong&gt; or &lt;strong&gt;author actions&lt;/strong&gt; as high priority and flag them. This will put them at the top of your inbox:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/effective-github-notifications/images/Github-1.png&#34;
    alt=&#34;Configuring Github high priority email notifications in Apple mail&#34;&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;change-the-colour-of-medium-priority-items-so-they-stand-out&#34;&gt;Change the colour of medium priority items so they stand out&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Comments&lt;/strong&gt;, &lt;strong&gt;your activity&lt;/strong&gt;, and when a &lt;strong&gt;team mentions&lt;/strong&gt; you are in is mentioned.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/effective-github-notifications/images/Github-2.png&#34;
    alt=&#34;Configuring Github medium priority email notifications in Apple mail&#34;&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;hide-low-priority-notifications&#34;&gt;Hide low priority notifications&lt;/h2&gt;
&lt;p&gt;Things you might want to go and check once in a while but aren&amp;rsquo;t directly involved in we can put in a folder so they don&amp;rsquo;t demand attention throughout the day.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/effective-github-notifications/images/Github-3.png&#34;
    alt=&#34;Hiding Github low priority email notifications in Apple mail&#34;&gt;
&lt;/figure&gt;

&lt;p&gt;What you should end up with after doing this is an inbox that shows you all the things that need your attention or you&amp;rsquo;d be interested, but hides the everyday torrent of Github spam in a folder that you can check if you want later.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/effective-github-notifications/images/Github-4.png&#34;
    alt=&#34;Notifications in action in Apple Mail&#34;&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Simple Sourdough Bread</title>
      <link>https://willj.net/posts/simple-sourdough-bread/</link>
      <pubDate>Wed, 13 Jan 2021 02:53:53 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/simple-sourdough-bread/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/Hero.jpg#full&#34; alt=&#34;Two sourdough boules&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/Search.jpg#right&#34; alt=&#34;Two sourdough boules&#34;&gt;&lt;/p&gt;
&lt;p&gt;I make sourdough bread usually at least once a week and sometimes post pictures of the result to &lt;a href=&#34;https://twitter.com/will_j&#34;&gt;Twitter&lt;/a&gt; and get asked pretty frequently about my technique. There&amp;rsquo;s a lot written about sourdough bread on the Internet these days, and plenty of YouTube videos on the subject too, but my technique is slightly different to many of them in that it is simple and takes the smallest amount of time possible while still getting great results. I don&amp;rsquo;t have the time to dedicate an entire week to the creation of a loaf of bread, I haven&amp;rsquo;t the patience to softly sing to the dough five times a day, and will not be spending several hours gently cupping the proving basket whispering encouraging thoughts long into the night.&lt;/p&gt;
&lt;p&gt;I have other stuff to do. So, my technique reqires the minimum amount of time. In total a loaf using my technique takes about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Day 1: about 10 minutes total.&lt;/li&gt;
&lt;li&gt;Day 2: 40 minutes to bake + oven pre-heat time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even this seems like a long time, but bear in mind that a lot of this time is spent waiting, for instance the baking and oven warming which is time you can spend doing other important stuff like making lunch, or endlessly doom-scrolling through Twitter.&lt;/p&gt;
&lt;p&gt;Though it&amp;rsquo;s fashionable to add your entire life story as the preamble to any recipe posted on the Web these days, let&amp;rsquo;s draw a line under this introduction and move on to the method. If you&amp;rsquo;re pushed for time to make bread then you&amp;rsquo;re not going to want to read about how a particularly nutty focaccia I ate when I was four set me on the path to posting marginally iterative recipes that I&amp;rsquo;ve made my own &amp;ldquo;with a twist&amp;rdquo; many years later.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-starter&#34;&gt;The starter&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;re going to need a starter. If you&amp;rsquo;ve not got one already, &lt;a href=&#34;https://willj.net/posts/making-a-sourdough-starter/&#34;&gt;head over to my article on making one&lt;/a&gt;, otherwise, read on!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-method&#34;&gt;The Method&lt;/h2&gt;
&lt;p&gt;You will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;250g strong white bread flour&lt;/li&gt;
&lt;li&gt;7g salt (about 1 teaspoon for table salt)&lt;/li&gt;
&lt;li&gt;115g water (I just experimented and got to this point, vary the water for the flour you use)&lt;/li&gt;
&lt;li&gt;1 or 2 teaspoons honey (optional)&lt;/li&gt;
&lt;li&gt;150g starter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I recommend starting off with white bread, it seems easier to make, but for wholemeal replace the flour above with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;200g strong white bread flour&lt;/li&gt;
&lt;li&gt;50g wholemeal flour&lt;/li&gt;
&lt;li&gt;30g mixed grains and seeds&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;day-1&#34;&gt;Day 1&lt;/h3&gt;
&lt;p&gt;Stir the starter before use in case it has separated at all. If any water has accumulated, stir that in too. Put all the ingredients into a bowl and mix. Once mixed you need to knead it. I use a stand mixer (kitchenaid) on setting 2 for 5 minutes. Hand kneading works too, but it&amp;rsquo;s harder to fiddle with your phone while you do it and you&amp;rsquo;ll need to knead for more like 10 minutes.&lt;/p&gt;
&lt;div class=&#34;youtube-embed&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/U8mvFYiuvqs?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; title=&#34;Me making sourdough&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;While the bread is kneading, or afterwards if you&amp;rsquo;re doing it by hand, top up the starter with 75g flour and 75g water. If you used more than 150g starter, for instance if you made a larger loaf, alter these quantities respectively. Mix, cover with your cloth and put back in the fridge.&lt;/p&gt;
&lt;p&gt;After kneading do a few stretch and folds (see elsewhere for description), then leave the dough in the bowl covered with a slightly damp tea towel at room temperature for several hours, eight is good to aim for. I often make bread sometime between 11 AM and early evening, then deal with it at about 10PM, but it&amp;rsquo;s pretty robust. You can leave it a longer or shorter time and it should be fine. Don&amp;rsquo;t leave it out overnight, it will develop a dry crust. If you forget and do leave it out overnight though, don&amp;rsquo;t worry about it, you can still use it, it might just not be as good.&lt;/p&gt;
&lt;p&gt;That evening, take the dough and do some &amp;ldquo;stretches&amp;rdquo;. Take one side of the dough, stretch it over to the other side and attach. rotate the dough, repeat. You should start to feel the dough slightly stiffen or harden. This step doesn&amp;rsquo;t take too long, just get a feel for it.&lt;/p&gt;
&lt;p&gt;Now, put it in the fridge. I use a banneton, they&amp;rsquo;re about £12 on amazon, but you can probably use some other dish. Flour the inside of it, drop the dough top of the loaf side down in the receptacle, cover, place in the fridge overnight.&lt;/p&gt;
&lt;p&gt;These steps in total will take about 10 minutes for the initial mix and a few minutes for the step in the evening.&lt;/p&gt;
&lt;h3 id=&#34;day-2&#34;&gt;Day 2&lt;/h3&gt;
&lt;figure class=&#34;right&#34;&gt;&lt;img src=&#34;https://willj.net/posts/simple-sourdough-bread/images/finished_bread.jpg&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;A finished loaf.&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The next day at some point (there&amp;rsquo;s no hard rules about how long to leave it), take the dough out of the fridge, pre-heat the oven to 250°C with a lidded dutch oven inside or similar, lined with baking paper.&lt;/p&gt;
&lt;p&gt;When the oven is up to temperature take the dough out of the banneton, score it to help it rise (I find a serrated knife works best for this) then plop into the hot cooking pot. Put the lid on, put it in the oven then turn the oven down to 200 (if you forget this step you will end up with a sourdough rock) and set a timer for 20 minutes.&lt;/p&gt;
&lt;p&gt;When 20 minutes is up, remove the lid and set the timer for 20 minutes again. When that timer is up it&amp;rsquo;s done, take everything out of the oven and place the bread on a wire cooking rack. Or just balance it on the handle of the cooking pot, this isn&amp;rsquo;t a cooking show, no-one cares.&lt;/p&gt;
&lt;p&gt;Leave it to mostly cool down before you cut it to prevent it from drying out as the steam escapes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;tips-and-examples&#34;&gt;Tips and examples&lt;/h2&gt;
&lt;h3 id=&#34;keeping-it&#34;&gt;Keeping it&lt;/h3&gt;
&lt;p&gt;The bread is best on the day of baking, but leave it to cool before eating it. If you want to keep it longer than one day I recommend slicing it and freezing it. It makes great toast later.&lt;/p&gt;
&lt;h3 id=&#34;tips&#34;&gt;Tips&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use good quality strong or very strong white bread flour if you&amp;rsquo;ve got it. It&amp;rsquo;s harder to get it to work with &amp;ldquo;fancy&amp;rdquo;, darker or lower quality flours. I use this: &lt;a href=&#34;https://www.shipton-mill.com/bulk-shop/canadian-strong-white.htm&#34;&gt;https://www.shipton-mill.com/bulk-shop/canadian-strong-white.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you use an enamelled dutch oven you may destroy the enamel over time in the hot oven, use a cheaper le crueset knock-off, or one without enamelling.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t stress timings too much, a few hours either way is probably fine on any of the steps. It should work around your schedule.&lt;/li&gt;
&lt;li&gt;Keep the starter in the fridge.&lt;/li&gt;
&lt;li&gt;Different flours need different amounts of water, you just have to experiment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;examples&#34;&gt;Examples&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s some photos of what the end result should look like on my almost never updated instagram:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.instagram.com/willj9000&#34;&gt;https://www.instagram.com/willj9000&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;or twitter, for example:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/will_j/status/1265263352244289537/photo/1&#34;&gt;https://twitter.com/will_j/status/1265263352244289537/photo/1&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;if-you-want-to-make-more-than-one-loaf-or-a-larger-loaf&#34;&gt;If you want to make more than one loaf, or a larger loaf&lt;/h3&gt;
&lt;p&gt;Start to feed the starter with 50/50 flour and water a few days in advance until you have enough starter to take out the amount you will need while still leaving about 150g that you can then feed and put back in the fridge.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Making a Sourdough Starter</title>
      <link>https://willj.net/posts/making-a-sourdough-starter/</link>
      <pubDate>Wed, 13 Jan 2021 02:53:52 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/making-a-sourdough-starter/</guid>
      <description>&lt;p&gt;The absolutely best way of making a starter if you don&amp;rsquo;t already have one is to not make one at all. If you can, ask someone who already has one for a bit of theirs. Most people will be happy to donate a bit, and this is a far shorter way of starting. There&amp;rsquo;s nothing heroic about creating your own, it&amp;rsquo;s mostly just a pain in the butt. If you&amp;rsquo;ve not got one though, here&amp;rsquo;s how make your own.&lt;/p&gt;
&lt;p&gt;Already made your starter and want to make bread? &lt;a href=&#34;https://willj.net/posts/simple-sourdough-bread/&#34;&gt;Head over to the bread recipe!&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;things-you-will-need&#34;&gt;Things you will need&lt;/h2&gt;
&lt;figure class=&#34;right&#34;&gt;&lt;img src=&#34;https://willj.net/posts/making-a-sourdough-starter/images/the_jar.jpg&#34;
    alt=&#34;Sourdough container with a banana propped against it at a jaunty angle&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;My sourdough container, banana for scale.&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;To make a starter you&amp;rsquo;ll need only four things.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Flour&lt;/li&gt;
&lt;li&gt;Water&lt;/li&gt;
&lt;li&gt;Something to keep it in&lt;/li&gt;
&lt;li&gt;Patience&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;rsquo;s it! nothing fancy required. For the most reliable results I recommend using good quality, fresh flour. Don&amp;rsquo;t use the stuff that&amp;rsquo;s a year out of date you found at the back of the cupboard. It might work, but I&amp;rsquo;ve had more luck with good quality fresh flour.&lt;/p&gt;
&lt;p&gt;The container should be a glass, plastic or non-reactive metal, about one banana in height (see image). It should be very clean and free from dirt or any cleaning product residue. You will also need some sort of cloth to cover it, and an elastic band to keep the cloth in place.&lt;/p&gt;
&lt;h2 id=&#34;the-method&#34;&gt;The Method&lt;/h2&gt;
&lt;p&gt;Make sure to be exact with the measurements, no eyeballing quantities or using weird measurements like &amp;ldquo;cups&amp;rdquo; or anything like that. Also, use a set of digital scales with 1g accuracy if you can, they make baking much easier.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/making-a-sourdough-starter/images/starter_progress.jpg&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Sourdough progression. Inactive starter on the left, some activity in the middle, the same starter 24 hours later.&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&#34;day-1&#34;&gt;Day 1&lt;/h3&gt;
&lt;p&gt;Mix 50g water (around tap temperature is fine) with 50g flour until you get a smooth paste. Cover with a cloth and leave out at room temperature somewhere it will not get too hot or cold for about 24 hours, so not in the fridge or a sunny windowsill.&lt;/p&gt;
&lt;h3 id=&#34;day-2&#34;&gt;Day 2&lt;/h3&gt;
&lt;p&gt;Mix 50g flour and 50g water as on day 1 into the existing mixture, cover and leave for another 24 hours&lt;/p&gt;
&lt;h3 id=&#34;day-3-through-7&#34;&gt;Day 3 through 7&lt;/h3&gt;
&lt;p&gt;Repeat the process from day 2.&lt;/p&gt;
&lt;p&gt;You should start to see some bubbling activity on about day 4 and if everything went right you should have a starter after about a week. You should end up with something that smells slightly sour and a bit like yoghurt.&lt;/p&gt;
&lt;p&gt;It might take a little bit longer, it&amp;rsquo;s going to depend on the flour and temperature. If it&amp;rsquo;s not doing anything by about two weeks or it smells like it&amp;rsquo;s gone off then you might need to restart.&lt;/p&gt;
&lt;p&gt;Once it&amp;rsquo;s done, keep the cloth cover on and put it in the fridge until you need it. It will keep about a week without attention in a cold fridge.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&#34;left&#34;&gt;&lt;img src=&#34;https://willj.net/posts/making-a-sourdough-starter/images/completed_starter.jpg&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;A working starter.&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;right&#34;&gt;&lt;img src=&#34;https://willj.net/posts/making-a-sourdough-starter/images/starter_with_lid.jpg&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Use a cloth lid for your starter to allow it to breath.&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;maintaining-your-starter&#34;&gt;Maintaining your starter&lt;/h2&gt;
&lt;p&gt;As long as you keep taking some out and then topping it up, the starter should last forever.&lt;/p&gt;
&lt;p&gt;I found that my starter keeps best when kept in the fridge as it turns over too fast when any warmer.&lt;/p&gt;
&lt;p&gt;When you use some of the starter, replace what you took with 50/50 water and flour. For example, if you take 150g starter to make a loaf of bread, replace what you took with 75g water and 75g flour. Try to keep the ratios exact. If you bias towards more water for instance each time you&amp;rsquo;re going to end up with wet bread, but bear in mind that over time your starter will suffer from evaporation, so you may need to add a little extra water every once in a while.&lt;/p&gt;
&lt;p&gt;If you think you might want to make a larger, or multiple loaves in a few days, just add more water and flour over a couple of days until you&amp;rsquo;ve got the amount of starter you will need without taking too much.&lt;/p&gt;
&lt;p&gt;When you take the starter out ideally it will be fairly stiff and coagulated, see about 30s into this video (you don&amp;rsquo;t have to stir it for ages, I was just fiddling). Ignore the rest of the video, my technique has changed in some spots, see the &lt;a href=&#34;https://willj.net/posts/simple-sourdough-bread/&#34;&gt;bread recipe&lt;/a&gt; for the updated method.&lt;/p&gt;
&lt;div class=&#34;youtube-embed&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/7OCz-usKlgc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; title=&#34;Me making sourdough&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;The starter should be good to use every day, but if you don&amp;rsquo;t need to make bread for a while it should keep in the fridge for over a week without use. When it&amp;rsquo;s been left for longer than that without being refreshed you can still make bread with it, but it gets harder to get good results. If you leave it too long though it might die and you&amp;rsquo;ll need to start from scratch.&lt;/p&gt;
&lt;p&gt;If your starter has sat for a while then you will find it will become more liquid, this is OK, you can still make bread with it, it just might not be as good. If there is liquid sitting on top of the starter, mix it in. If you pour it out your starter will be unbalanced.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Using the T67XX CO₂ Sensor Module in Go</title>
      <link>https://willj.net/posts/using-the-t67xx-co2-sensor-module-in-go/</link>
      <pubDate>Mon, 30 Nov 2020 11:24:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/using-the-t67xx-co2-sensor-module-in-go/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/T67XX.png#right&#34; alt=&#34;T67XX CO₂ sensor datasheet cover&#34;&gt;&lt;/p&gt;
&lt;p&gt;So, you bought four T67XX CO₂ sensors and only once they were delivered started to work out how to get values from them huh? Well I&amp;rsquo;m right there with you because so did I. and I carefully deposited the results in a new Go lib. Announcing the &lt;a href=&#34;https://github.com/wjessop/T67XX&#34;&gt;Go T67XX CO₂ sensor library&lt;/a&gt;! This post will give you some details about what these sensors can do, then introduce the library and how to use it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;unit-specs&#34;&gt;Unit specs&lt;/h3&gt;
&lt;p&gt;I got my devices (I think mine are T6713) from &lt;a href=&#34;https://www.aliexpress.com/item/32322544929.html?spm=a2g0s.9042311.0.0.7fcf4c4dwbubog&#34;&gt;AliExpress&lt;/a&gt;, and there are specs on the page there, but some interesting specs to highlight would be:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Measurement Range&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;0 to 5000 ppm&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Accuracy&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;400-5000 ppm ± 75 ppm or 10% of reading, whichever is greater&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Signal Update&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Every 5 second&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Response Time&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;&amp;lt; 3 minutes for 90% step change typical&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Warm Up Time&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;&amp;lt; 2 minutes (operational), 10 minutes (maximum accuracy)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Connection&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;I²C slave up to 100 kHz, UART @ 19200 Baud w/Modbus support&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Power Requirements&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;4.5-5.5 VDC, Peak 200mA (155mA typical), Average 25mA (20mA typical)&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This sensor is likely good enough for most home uses like just ensuring you&amp;rsquo;re getting enough fresh air during the day, and this is what I&amp;rsquo;m using it for:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/graph.png#full&#34; alt=&#34;graph of CO₂ data&#34;&gt;&lt;/p&gt;
&lt;p&gt;There is more data available on &lt;a href=&#34;files/Manual-AMP-0002-T6713-Sensor.pdf&#34;&gt;the datasheet&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;connecting-it-up&#34;&gt;Connecting it up&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m using it connected to an &lt;a href=&#34;https://en.wikipedia.org/wiki/I%C2%B2C&#34;&gt;I²C bus&lt;/a&gt; on my Raspberry Pi 4, so although there are a few modes of connecting the sensor that&amp;rsquo;s the one I&amp;rsquo;m focussing on. To do this. I connected the pins as follows:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/connections.png#right&#34; alt=&#34;T67XX CO₂ sensor datasheet cover&#34;&gt;&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Pin&lt;/th&gt;
          &lt;th&gt;Function&lt;/th&gt;
          &lt;th&gt;Raspberry Pi 4 pin&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;SDA&lt;/td&gt;
          &lt;td&gt;3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;SCL&lt;/td&gt;
          &lt;td&gt;5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;V++&lt;/td&gt;
          &lt;td&gt;4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;GND&lt;/td&gt;
          &lt;td&gt;6&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;PWM&lt;/td&gt;
          &lt;td&gt;Not connected&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;6&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;CTRL/TEST&lt;/td&gt;
          &lt;td&gt;6 (Also GND)&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Whatever you do, don&amp;rsquo;t connect them backwards as this sensor seems to be particularly sensitive to being misconnected (I did this and accidentally let the magic smoke out of one of them). I used a &lt;a href=&#34;https://www.adafruit.com/product/757&#34;&gt;level shifter&lt;/a&gt; to switch the 3.3v lines to 5v because I didn&amp;rsquo;t have any 4.7k resistors and this is what worked for me, though the unit should work at 3.3v, from the datasheet:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is an internal pull up resistor on pin 1 of the I2C interface. Customer will need to provide an external pull up resistor on pin 2 with a recommended value of 4.7k. I2C interface can operate at both 3.3V and 5V logic levels.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;images/connected.jpg#full&#34; alt=&#34;The sensor connected and displaying the CO₂ reading on an LCD&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;using-the-sensor-with-the-t67xx-go-library&#34;&gt;Using the sensor with the T67XX Go library&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not going to go into the details of how the library works, there are docs and examples over at &lt;a href=&#34;https://github.com/wjessop/T67XX&#34;&gt;the T67XX Github page&lt;/a&gt;, but at a high level, given a connection to the I²C bus it can read CO₂ data and perform management tasks. Here&amp;rsquo;s a simple program that waits for the sensor to achieve full accuracy then reads CO₂ values from it every 10 seconds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/wjessop/t67xx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;golang.org/x/exp/io/i2c&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// We can change the sensor address on the bus if we want to, but it defaults&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// to 0x21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;t67XXSensorAddress&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;0x21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Open an i2c bus that we can pass to the driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;device&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i2c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i2c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Devfs&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Dev&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/dev/i2c-1&amp;#34;&lt;/span&gt;}, &lt;span style=&#34;color:#a6e22e&#34;&gt;t67XXSensorAddress&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatalf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Couldn&amp;#39;t open the T67XX sensor at %x, error was %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;t67XXSensorAddress&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Create the driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;t67xx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;T67XX&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Device&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// For now the library needs a logger to be provided. It needs to satisfy the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// following interface:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// type Logger interface {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// 	Debug(...interface{})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// 	Debugf(string, ...interface{})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// 	Fatalf(string, ...interface{})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Stderr&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;T67XX&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;LstdFlags&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetLogger&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// EnableABC enables the ABC calibration. From the datasheet:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//   &amp;#34;ABC LOGIC™ Automatic Background Logic, or ABC Logic™, is a patented&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    self-calibration technique that is designed to be used in applications where&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    concentrations will drop to outside ambient conditions (400 ppm) at least&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    three times in a 7 days, typically during unoccupied periods. Full accuracy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    to be achieved utilizing ABC Logic™. With ABC Logic™ enabled, the sensor will&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    typically reach its operational accuracy after 24 hours of continuous&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    operation at a condition that it was exposed to ambient reference levels of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    air at 400 ppm CO2. Sensor will maintain accuracy specifications with ABC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    Logic™ enabled, given that it is at least four times in 21 days exposed to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    the reference value and this reference value is the lowest concentration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    to which the sensor is exposed. ABC Logic™ requires continuous operation of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    the sensor for periods of at least 24 hours.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    Note: Applies when used in typical residential ambient air. Consult Telaire&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;//    if other gases or corrosive agents are part of the application environment.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;EnableABC&lt;/span&gt;(); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Could not enable ABC calibration on the sensor&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Create a signal channel that will be closed when the sensor reaches full accuracy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;accuracyChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;t67xx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;T67XX&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;// Sleep in the background until the sensor has been powered up long enough&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;// to achieve full accuracy.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SleepUntilFullAccuracy&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error sleeping until full accuracy&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;// Close the signal channel then exit the goroutine as we no-longer need it.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		close(&lt;span style=&#34;color:#a6e22e&#34;&gt;accuracyChan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}(&lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Now we can read the CO₂ readings in a loop, taking care to discard any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// spurious readings.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;accuracyChan&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;// A successful read on the closed channel indicates that the sensor is&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;// now fully accurate.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;co2Reading&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GasPPM&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;// The sensors I have sometimes give spurious readings. Let&amp;#39;s discount them.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;// Adjust these values based on the baseline CO₂ reading you expect. The max is&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;// the measurement limit according to the datasheet, but i&amp;#39;ve seen values well&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;// over 10,000.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;co2Reading&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;co2Reading&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Reading of %d from CO₂ sensor was out of allowed bounds&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;co2Reading&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Got CO₂ reading of %d from CO₂ sensor&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;co2Reading&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Skipping CO₂ reading as the sensor has not yet achieved full accuracy&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it! There&amp;rsquo;s a few more functions that the library provides, such as enabling calibration and setting the I²C bus address, you can check them out at the repo.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Custom 3D printed Blue Snowball desk stand</title>
      <link>https://willj.net/posts/custom-blue-snowball-microphone-desk-stand/</link>
      <pubDate>Wed, 25 Nov 2020 04:59:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/custom-blue-snowball-microphone-desk-stand/</guid>
      <description>&lt;h1 id=&#34;introducing-an-all-new-super-sleek-blue-snowball-microphone-desk-stand&#34;&gt;Introducing, an all-new, super-sleek Blue Snowball microphone desk stand!&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;images/blue_snowball_0.jpg#left&#34; alt=&#34;Blue snowball microphone on the new stand&#34;&gt;
&lt;img src=&#34;images/microphone_stand_0.jpg#right&#34; alt=&#34;Closeup of the blue snowball stand showing the threads&#34;&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s very nice Will, but why?&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;images//blue_snowball_1.jpg#right&#34; alt=&#34;Blue Snowball microphone in the way of my monitor&#34;&gt;&lt;/p&gt;
&lt;p&gt;I inherited a unwanted Blue Snowball from &lt;a href=&#34;https://37signals.com/&#34;&gt;an old employer&lt;/a&gt; several years ago, and it&amp;rsquo;s been a really fantastic addition to my day to day kit, especially as the number of video calls has increased in recent years. The only problem I had with the microphone started when I upgraded my monitors to some portrait orientation screens. These come almost all the way down to the desk, and as a result the (in my opinion rather ugly) original Blue Snowball microphone stand rather got in the way, even at it&amp;rsquo;s shortest setting.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&#34;images//blue_snowball_2.jpg#right&#34; alt=&#34;Blue Snowball microphone lying on it&amp;rsquo;s side&#34;&gt;&lt;/p&gt;
&lt;p&gt;I was able to &amp;ldquo;fix&amp;rdquo; the problem of the microphone being in the way by laying the microphone flat. This wasn&amp;rsquo;t ideal, it took up a lot more room, looked bad, and made it sound like I was lying down. Still, it worked for long enough.&lt;/p&gt;
&lt;h2 id=&#34;the-solution&#34;&gt;The Solution&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m always looking for a problem where the solution is &amp;ldquo;3D print something&amp;rdquo;, and this seemed like a perfect fit. An hour with Fusion 360 later and I had a stand I liked.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images//blue_snowball_0.jpg#left&#34; alt=&#34;Blue snowball microphone on the new stand, side view&#34;&gt;
&lt;img src=&#34;images//blue_snowball_3.jpg#left&#34; alt=&#34;Blue snowball microphone on the new stand, front view&#34;&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m really happy with it, it fulfils all the criteria I had when I started designing it, and I&amp;rsquo;m particularly happy with the way it looks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is as minimalistic as possible. I don&amp;rsquo;t want clutter.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s also fairly elegant in terms of looks (in my opinion of course), I have to look at this thing every day.&lt;/li&gt;
&lt;li&gt;Fits the screw threads on the Blue Snowball mic. I want to position it myself and don&amp;rsquo;t want it swivelling around if a cable gets nudged.&lt;/li&gt;
&lt;li&gt;Rises as low as possible above the desk. I don&amp;rsquo;t want it blocking the view of my monitors.&lt;/li&gt;
&lt;li&gt;Allows room for the microphone to be tilted without the cable fouling on the desk.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;print-one-yourself&#34;&gt;Print one yourself&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve uploaded the STL files for you to print yourself. There&amp;rsquo;s the &lt;a href=&#34;files/blue_snowball_desk_stand/Blue%20snowball%20desk%20stand%20v3.stl&#34;&gt;v3 design&lt;/a&gt; which is the one I use, and the &lt;a href=&#34;files/blue_snowball_desk_stand/Blue%20snowball%20desk%20stand%20v5.stl&#34;&gt;v5 design&lt;/a&gt;. The two versions are very similar, the difference is only that the v3 version has a curved underside, and the v5 version has been designed to not require a support structure while printing. V3 is my preferred version and is probably less prone to wobble.&lt;/p&gt;
&lt;p&gt;If you are printing these yourself due to the fine thread you will likely want to use a fairly high quality print setting.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Welcome to My New Blog</title>
      <link>https://willj.net/posts/welcome-to-my-new-blog/</link>
      <pubDate>Wed, 24 Jun 2020 23:30:40 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/welcome-to-my-new-blog/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://willj.net/img/posts/me_rotterdam_round.png#right&#34; alt=&#34;Me in Rotterdam&#34;&gt;&lt;/p&gt;
&lt;p&gt;Welcome to my new site! If you want to see my old writings you can still find them at &lt;a href=&#34;https://blog.willj.net/&#34;&gt;my Wordpress blog site&lt;/a&gt; which is still up. I may at some point attempt to copy the posts over from there, but I don&amp;rsquo;t have time right now.&lt;/p&gt;
&lt;p&gt;Anyway, thanks for checking out my new site!&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Writing to an Lcd Panel Using Go and a Raspberry Pi</title>
      <link>https://willj.net/posts/writing-to-an-lcd-panel-using-go-and-a-raspberry-pi/</link>
      <pubDate>Wed, 24 Jun 2020 02:09:43 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/writing-to-an-lcd-panel-using-go-and-a-raspberry-pi/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://willj.net/img/posts/lcd.jpg#right&#34; alt=&#34;LCD display showing climate data&#34;&gt;&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&#34;https://willj.net/posts/humidity-temperature-and-pressure-sensing-on-a-raspberry-pi-with-go/&#34;&gt;last post&lt;/a&gt; I wrote about how I rigged up a Raspberry Pi to monitor temperature, humidity and air pressure. In this post I will talk about how I added a multiline LCD display into the mix to display the same data on a multiline LCD display.&lt;/p&gt;
&lt;h3 id=&#34;why-tho&#34;&gt;Why tho&lt;/h3&gt;
&lt;p&gt;Why indeed! It&amp;rsquo;s not particularly useful, I know it&amp;rsquo;s too hot in my office already just by, well, feeling the air, and I can always check out the Grafana dashboard I put together to get the latest data if I need to know an exact figure, which I don&amp;rsquo;t. It&amp;rsquo;s quite &lt;em&gt;interesting&lt;/em&gt; to know how hot it is in here (my wife &lt;em&gt;definitely&lt;/em&gt; agrees on this) and just being able to know by glancing at an LCD display is quite convenient.&lt;/p&gt;
&lt;p&gt;But that&amp;rsquo;s all irellevant. I did it because it was fun and having an LCD display stuff is cool.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://willj.net/img/posts/LCM1602-detail.jpg#left&#34; alt=&#34;YwRobot Arduino LCM1602 backpack&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;the-display&#34;&gt;The display&lt;/h3&gt;
&lt;p&gt;The display is an LCM1602 20 character by 4 line LCD. Attached to the back of the LCD is a &amp;ldquo;backpack&amp;rdquo;. This backpack connects to an &lt;a href=&#34;https://en.wikipedia.org/wiki/I%C2%B2C&#34;&gt;I²C bus&lt;/a&gt;, for example like the ones on either an Arduino or Raspberry Pi.&lt;/p&gt;
&lt;h3 id=&#34;making-the-dislay-show-text&#34;&gt;Making the dislay show text&lt;/h3&gt;
&lt;p&gt;This was the fun part of the challenge. There are some &lt;a href=&#34;https://www.circuitbasics.com/raspberry-pi-i2c-lcd-set-up-and-programming/&#34;&gt;Python code and libraries&lt;/a&gt; and at least one &lt;a href=&#34;https://github.com/johnrickman/LiquidCrystal_I2C&#34;&gt;C++ library&lt;/a&gt; out there that work mostly OK, but I don&amp;rsquo;t want to use Python, I want to use Go.&lt;/p&gt;
&lt;p&gt;So, rather than attempt to start from scratch and interpret &lt;a href=&#34;https://cdn-shop.adafruit.com/datasheets/TC1602A-01T.pdf&#34;&gt;the datasheet&lt;/a&gt; I decided try to convert some of the Python code to Go. This turned out to be pretty easy, even though I don&amp;rsquo;t really know Python at all.&lt;/p&gt;
&lt;p&gt;What I ended up with was my &lt;a href=&#34;https://github.com/wjessop/lcm1602_lcd&#34;&gt;Go LCM1602 LCD driver&lt;/a&gt; project. This library is pretty simple to use, as can be seen from the example code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lcd&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/wjessop/lcm1602_lcd&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Configure this line with the device location and address of your device&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lcdDevice&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i2c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i2c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Devfs&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Dev&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/dev/i2c-1&amp;#34;&lt;/span&gt;}, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x27&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lcdDevice&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lcdDisplay&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;lcd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewLCM1602LCD&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lcdDevice&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Write a string to row 1, position 0 (ie, the start of the line)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lcdDisplay&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteString&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello World!&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Write a string to row 2, position 7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lcdDisplay&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteString&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(&amp;gt;&amp;#39;.&amp;#39;&amp;lt;)&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lcdDisplay&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Clear&lt;/span&gt;(); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The only feature not documented here is the &lt;code&gt;WritePaddedString&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// WritePaddedString writes a string to the LCD at the given row, but pads the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// row to effectively wipe any remaining characters off the line. This is handy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// for when you want to repeatedly display data on a line, but it could be of&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// varying length, and you don&amp;#39;t want to blank the entire screen each time.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;LCM1602LCD&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;WritePaddedString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;row&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;startPosition&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%-20v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;row&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;startPosition&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once I&amp;rsquo;d written the library it was a simple job to incorporate it into the climate monitoring program I&amp;rsquo;d created, and you can see this in the &lt;a href=&#34;https://github.com/wjessop/rpi_go_bme280_example&#34;&gt;full working example&lt;/a&gt; I uploaded to GitHub.&lt;/p&gt;
&lt;h3 id=&#34;thats-it&#34;&gt;That&amp;rsquo;s it!&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ll probably keep the LCD displaying climate data in my office, as I&amp;rsquo;m basically addicted to knowing what the temperature and humidity is now. If you decide to get your own LCD screen, make sure you grab one that has the backpack, as you&amp;rsquo;ll have a hard time using it if it doesn&amp;rsquo;t have one.&lt;/p&gt;
&lt;p&gt;Just for fun, here&amp;rsquo;s a photo of the back of the LCD with the backlight shining through the circuit board:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://willj.net/img/posts/LCM1602-backlight.jpg&#34;&gt;&lt;img src=&#34;https://willj.net/img/posts/LCM1602-backlight.jpg#full&#34; alt=&#34;YwRobot Arduino LCM1602 backpack&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Humidity, Temperature and Pressure Sensing on a Raspberry Pi With Go</title>
      <link>https://willj.net/posts/humidity-temperature-and-pressure-sensing-on-a-raspberry-pi-with-go/</link>
      <pubDate>Tue, 23 Jun 2020 20:26:10 +0100</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/humidity-temperature-and-pressure-sensing-on-a-raspberry-pi-with-go/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://willj.net/img/posts/climate.png&#34;&gt;&lt;img src=&#34;https://willj.net/img/posts/climate.png#full&#34; alt=&#34;Office climate graphs&#34;&gt;&lt;/a&gt; (click for a higher resolution image)&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;background&#34;&gt;Background&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://willj.net/img/posts/buddhas-hand.jpg#right&#34; alt=&#34;Buddha&amp;rsquo;s Hand&#34;&gt;&lt;/p&gt;
&lt;p&gt;A few months ago I bought a couple of lemon trees to grow in my conservatory, but most excitingly for me, a &lt;a href=&#34;https://en.wikipedia.org/wiki/Buddha%27s_hand&#34;&gt;Buddha&amp;rsquo;s hand tree&lt;/a&gt;. This tree was fairly expensive, and I wanted to maximise it&amp;rsquo;s chances of surviving and hopefully thriving. Citrus trees are quite sensitive to extremes of temperature (they obviously don&amp;rsquo;t like cold, but apparently don&amp;rsquo;t like excess heat either) and also humidity, preferring an atmosphere of around 50% relative humidity or more.&lt;/p&gt;
&lt;p&gt;It was for this reason that I decided to start experimenting with climate monitoring.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;the-hardware&#34;&gt;The Hardware&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://willj.net/img/posts/BME280.jpg#left&#34; alt=&#34;BME280 sensor&#34;&gt;&lt;/p&gt;
&lt;p&gt;I was originally planning on making some sensor units as described in &lt;a href=&#34;https://github.com/tenderlove/esp8266aq&#34;&gt;Aaron Paterson&amp;rsquo;s ESP8266 + Plantower AQ sensor project&lt;/a&gt;, so I ordered a load of parts and PCBs to make those, but a lot of the parts for these sensor units are ordered from AliExpress, and so have delivery times in the order of weeks to months, rather than days, so given that my Buddha&amp;rsquo;s Hand tree had already arrived I decided to get some &lt;a href=&#34;https://www.amazon.co.uk/gp/product/B0799JRDKJ/ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&amp;amp;psc=1&#34;&gt;BME280 temperature, humidity and pressure sensors from Amazon&lt;/a&gt; as they don&amp;rsquo;t cost too much and would allow me to get a jump start on checking that my trees were safe.&lt;/p&gt;
&lt;p&gt;These BME280 sensors use &lt;a href=&#34;https://en.wikipedia.org/wiki/I%C2%B2C&#34;&gt;the I²C bus&lt;/a&gt;, which makes them really easy to connect to, and read, from an Arduino or Raspberry Pi. I have both hanging around, but the Raspberry Pi is easier to get something quick running because I can write my code in a higher level language and it comes with Wifi onboard. Using the raspberry pi meant that the equipment list I needed was small.&lt;/p&gt;
&lt;h4 id=&#34;required-equipment&#34;&gt;Required equipment&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Raspberry Pi&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.amazon.co.uk/gp/product/B0799JRDKJ/ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&amp;amp;psc=1&#34;&gt;BME280 sensor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.amazon.co.uk/Aukru-20cm-Female-Female-Jumpers-Raspberry/dp/B00OL6JZ3C/ref=pd_sbs_23_2/257-1678062-8665147?_encoding=UTF8&amp;amp;pd_rd_i=B00OL6JZ3C&amp;amp;pd_rd_r=2d8fad77-74b0-4e22-885d-482ee519390b&amp;amp;pd_rd_w=kq16h&amp;amp;pd_rd_wg=GYNJU&amp;amp;pf_rd_p=2773aa8e-42c5-4dbe-bda8-5cdf226aa078&amp;amp;pf_rd_r=PQ2X10H9H3VV3FCWCM1B&amp;amp;psc=1&amp;amp;refRID=PQ2X10H9H3VV3FCWCM1B&#34;&gt;Wire to connect the sensor to the Raspberry pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Power supply for the Pi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wiring the sensor was pretty easy. You can find &lt;a href=&#34;https://www.element14.com/community/docs/DOC-92640/l/raspberry-pi-4-model-b-default-gpio-pinout-with-poe-header&#34;&gt;Raspberry Pi pinout diagrams&lt;/a&gt; on the Web, and you just need to connect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VIN to DC Power 5v (pin 4)&lt;/li&gt;
&lt;li&gt;GND to Ground (pin 6)&lt;/li&gt;
&lt;li&gt;SCL to SCL1 (pin 5)&lt;/li&gt;
&lt;li&gt;SDA to SDA1 (pin 3)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s it! No complex electronics required for this setup.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;the-software&#34;&gt;The Software&lt;/h3&gt;
&lt;p&gt;I decided on using an &lt;a href=&#34;https://www.influxdata.com/&#34;&gt;Influx DB&lt;/a&gt; to store the data, and to graph the results in &lt;a href=&#34;https://grafana.com/&#34;&gt;Grafana&lt;/a&gt; (as &lt;a href=&#34;https://github.com/tenderlove/esp8266aq&#34;&gt;Aaron does for his monitoring&lt;/a&gt;) as they seemed like a good fit, and I didn&amp;rsquo;t want to spend too much time looking at alternatives as my trees were going unmonitored. They are also incredibly easy to connect to each other to see the time-series data in Influx DB in Grafana which helps a lot. There is handily an existing &lt;a href=&#34;https://simonhearne.com/2020/pi-influx-grafana/&#34;&gt;guide to installing Influx DB and Grafana on a Raspbery Pi 4&lt;/a&gt; already available, which made things a bit quicker.&lt;/p&gt;
&lt;p&gt;For the software to grab the sensor readings and put the data into Influx I used Go for a number of reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I like writing it&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s efficient. Raspberry Pis are faster than they used to be, but they&amp;rsquo;re still somewhat constrained&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s really easy to deploy to a Pi&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s really simple to make work with systemd&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In reality you can use whatever language you like, Ruby or Python would be fine as this isn&amp;rsquo;t a highly CPU or memory intensive application, but you are likely to want to choose a language that someone has already written a driver for the sensor in as that&amp;rsquo;s going to cut down the amount of time you have to spend writing the software &lt;strong&gt;a lot&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It just so happens that a couple of people have written Go libraries for the BME280, I chose &lt;a href=&#34;https://github.com/maciej/bme280&#34;&gt;this one&lt;/a&gt;. Putting it to use it&amp;rsquo;s fairly simple to get the data out of the sensor and print it to the terminal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Get sensor data from the BME280 and print it to the terminal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/maciej/bme280&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;golang.org/x/exp/io/i2c&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getBME280&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Driver&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;device&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i2c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i2c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Devfs&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Dev&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/dev/i2c-1&amp;#34;&lt;/span&gt;}, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x76&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;device&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;InitWith&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ModeForced&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Settings&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;Filter&lt;/span&gt;:                  &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FilterOff&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;Standby&lt;/span&gt;:                 &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StandByTime1000ms&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;PressureOversampling&lt;/span&gt;:    &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Oversampling16x&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;TemperatureOversampling&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Oversampling16x&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;HumidityOversampling&lt;/span&gt;:    &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Oversampling16x&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getBME280&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;response&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bme280&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Read&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Temp: %.1fC, Press: %.1fhPa, Hum: %.1f%%\n&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;response&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Temperature&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;response&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pressure&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;response&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Humidity&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To make this code work for yourself, write it to a file, compile it on your local machine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GOOS=linux GOARCH=arm GOARM=7 go build sensor.go -o sensor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copy it over to your Raspberry Pi, wherever that happens to be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ scp sensor pi@192.168.1.120:~/
tmp 100% 2096KB   4.4MB/s   00:00
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then SSH into your Raspberry Pi and after you have &lt;a href=&#34;https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-i2c&#34;&gt;made sure that i2c is enabled&lt;/a&gt; run the binary as root:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# sudo ./sensor
Temp: 22.4C, Press: 1000.0hPa, Hum: 54.8%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sweet! The next step is to get the data into Influx DB so we can log it and graph it with Grafana. To do that I used the &lt;a href=&#34;http://github.com/influxdata/influxdb-client-go&#34;&gt;Influx DB API provided by the Influx creators&lt;/a&gt; themselves. This looks something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;flag&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;influxdb2&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/influxdata/influxdb-client-go&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;lcd&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/wjessop/lcm1602_lcd&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;golang.org/x/exp/io/i2c&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;databaseName&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;climate&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;locationName&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;conservatory&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// create new client with default option for server url authenticate by token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;influxdb2&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewClient&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://127.0.0.1:8086&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;influxhost&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;climate-writer:&amp;lt;password goes here&amp;gt;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// user blocking write client for writes to desired bucket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;writeAPI&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteApiBlocking&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;databaseName&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;now&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Now&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Write a single datapoint to Infux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;influxdb2&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewPoint&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stat&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unit&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temperature&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;location&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;locationName&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;response&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Temperature&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;now&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;writeAPI&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WritePoint&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Repeat the above Influx write for humidity and pressure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have pushed &lt;a href=&#34;https://github.com/wjessop/rpi_go_bme280_example&#34;&gt;a full working example&lt;/a&gt; including reading the sensor data and sending to Influx DB to Github. It also includes optional writing of the climate data to an LCD panel.&lt;/p&gt;
&lt;p&gt;That is pretty much it! Place your Raspberry Pi with it&amp;rsquo;s sensor in the place you want to be monitored, and it will gather the data for you. Creating a Grafana dashboard is left as an exercise for the reader.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;the-finished-device&#34;&gt;The Finished Device&lt;/h3&gt;
&lt;p&gt;Here is the working sensor and Pi in place in my conservatory, running the Go program, Influx DB and Grafana. I have now added a second Pi in my study that reports it&amp;rsquo;s sensor readings to the Influx DB on this machine too.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://willj.net/img/posts/sensor-in-place.jpg#full&#34; alt=&#34;Raspberry Pi and attached sensor&#34;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;improvements&#34;&gt;Improvements&lt;/h3&gt;
&lt;p&gt;Raspberry Pis are fairly expensive, and have way more processing power than is needed to read sensor data, and they draw more power too. I plan on eventually putting together the boards in &lt;a href=&#34;https://github.com/tenderlove/esp8266aq&#34;&gt;Aarons project&lt;/a&gt; so I can put a few more of these around my house relatively cheaply, and with more sensor types. The Raspberry Pi is a great stop-gap though, and fine for a one-off. I may still run Influx and Grafana on a Pi.&lt;/p&gt;
&lt;p&gt;Because the Raspberry Pi was meant to be temporary I&amp;rsquo;ve left it bare, I&amp;rsquo;ll 3d print some cases for everything when my &lt;a href=&#34;https://shop.prusa3d.com/en/3d-printers/180-original-prusa-i3-mk3s-kit.html&#34;&gt;3d printer arrives&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&#34;https://willj.net/posts/writing-to-an-lcd-panel-using-go-and-a-raspberry-pi/&#34;&gt;next post&lt;/a&gt; I discuss how I added an LCD display to show the climate data.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Error installing libv8 on Mac OS Catalina</title>
      <link>https://willj.net/posts/error-installing-libv8-on-mac-os-catalina/</link>
      <pubDate>Mon, 17 Feb 2020 16:23:53 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/error-installing-libv8-on-mac-os-catalina/</guid>
      <description>&lt;p&gt;I got an error installing the libv8 gem on Catalina:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gem install libv8 -v &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;3.16.14.19&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building native extensions.  This could take a &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR:  Error installing libv8:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	ERROR: Failed to build gem native extension.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    current directory: /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/ext/libv8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/2.4.5/bin/ruby -r ./siteconf20200217-34155-18bho1v.rb extconf.rb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;creating Makefile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Applying /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/patches/disable-building-tests.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Applying /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/patches/disable-werror-on-osx.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Applying /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/patches/disable-xcode-debugging.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Applying /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/patches/do-not-imply-vfp3-and-armv7.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Applying /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/patches/do-not-use-MAP_NORESERVE-on-freebsd.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Applying /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/patches/do-not-use-vfp2.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Applying /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/patches/fPIC-for-static.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Compiling v8 &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; x64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Using python 2.7.16
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Using compiler: c++ &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;clang version 11.0.0&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unable to find a compiler officially supported by v8.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;It is recommended to use GCC v4.4 or higher
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Beginning compilation. This will take some time.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building v8 with env CXX&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;c++ LINK&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;c++  /usr/bin/make x64.release ARFLAGS.target&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;crs werror&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GYP_GENERATORS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;make &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;	build/gyp/gyp --generator-output&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;out&amp;#34;&lt;/span&gt; build/all.gyp &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;	              -Ibuild/standalone.gypi --depth&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;. &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;	              -Dv8_target_arch&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;x64 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;	              -S.x64  -Dv8_enable_backtrace&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; -Dv8_can_use_vfp2_instructions&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;true -Darm_fpu&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vfpv2 -Dv8_can_use_vfp3_instructions&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;true -Darm_fpu&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vfpv3 -Dwerror&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CXX&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;target&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/vendor/v8/out/x64.release/obj.target/preparser_lib/src/allocation.o
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;warning: include path &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; stdlibc++ headers not found; pass &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;-stdlib=libc++&amp;#39;&lt;/span&gt; on the command line to use the libc++ standard library instead &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wstdlibcxx-not-found&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file included from ../src/allocation.cc:33:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;../src/utils.h:33:10: fatal error: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;climits&amp;#39;&lt;/span&gt; file not found
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ^~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; warning and &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; error generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;: *** &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;/Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/vendor/v8/out/x64.release/obj.target/preparser_lib/src/allocation.o&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Error &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make: *** &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;x64.release&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Error &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/ext/libv8/location.rb:36:in &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;block in verify_installation!&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;: libv8 did not install properly, expected binary v8 archive &amp;#39;&lt;/span&gt;/Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/vendor/v8/out/x64.release/obj.target/tools/gyp/libv8_base.a&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;to exist, but it was not found (Libv8::Location::Vendor::ArchiveNotFound)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	from /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/ext/libv8/location.rb:35:in `each&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	from /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/ext/libv8/location.rb:35:in &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;verify_installation!&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	from /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19/ext/libv8/location.rb:26:in `install!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	from extconf.rb:7:in &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;extconf failed, exit code &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Gem files will remain installed in /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/gems/libv8-3.16.14.19 &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; inspection.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Results logged to /Users/will/.rbenv/versions/2.4.5/lib/ruby/gems/2.4.0/extensions/x86_64-darwin-19/2.4.0/libv8-3.16.14.19/gem_make.out
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-solution&#34;&gt;The Solution&lt;/h2&gt;
&lt;p&gt;The solution was as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install v8@3.15
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gem install libv8 -v &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;3.16.14.19&amp;#39;&lt;/span&gt; -- --with-system-v8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building native extensions with: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;--with-system-v8&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;This could take a &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Successfully installed libv8-3.16.14.19
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; gem installed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
      
      <item>
      <title>Fixing the ruby &#39;CoreFoundation/CFString.h&#39; file not found install error</title>
      <link>https://willj.net/posts/fixing-the-ruby-corefoundationcfstring.h-file-not-found-install-error/</link>
      <pubDate>Wed, 01 May 2019 15:00:33 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/fixing-the-ruby-corefoundationcfstring.h-file-not-found-install-error/</guid>
      <description>&lt;p&gt;I hit this error installing the latest Ruby using rbenv:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rbenv install 2.6.3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ruby-build: use openssl from homebrew
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Downloading ruby-2.6.3.tar.bz2...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-&amp;gt; https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.bz2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Installing ruby-2.6.3...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ruby-build: use readline from homebrew
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BUILD FAILED &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;OS X 10.14.4 using ruby-build 20190423&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Inspect or clean up the working tree at /var/folders/r7/kjzbwmx533b20hcf1_s9kc9c0000gn/T/ruby-build.20190501131413.33977
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Results logged to /var/folders/r7/kjzbwmx533b20hcf1_s9kc9c0000gn/T/ruby-build.20190501131413.33977.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Last &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; log lines:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling error.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling eval.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling file.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiling gc.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;file.c:23:10: fatal error: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;CoreFoundation/CFString.h&amp;#39;&lt;/span&gt; file not found
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; error generated.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make: *** &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;file.o&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Error &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make: *** Waiting &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; unfinished jobs....
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problem is missing headers. To re-install just run this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, Ruby should install just fine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rbenv install 2.6.3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ruby-build: use openssl from homebrew
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Downloading ruby-2.6.3.tar.bz2...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;gt;&lt;/span&gt; https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.bz2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Installing ruby-2.6.3...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ruby-build: use readline from homebrew
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Installed ruby-2.6.3 to /Users/will/.rbenv/versions/2.6.3 &lt;span style=&#34;color:#e6db74&#34;&gt;``&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
      
      <item>
      <title>Fixing errors installing the charlock_holmes ruby gem</title>
      <link>https://willj.net/posts/fixing-errors-installing-the-charlock_holmes-ruby-gem/</link>
      <pubDate>Wed, 13 Feb 2019 05:50:52 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/fixing-errors-installing-the-charlock_holmes-ruby-gem/</guid>
      <description>&lt;p&gt;The charlock_holmes gem can be a PITA to install on a mac, this is what worked for me. If you get this error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gem install charlock_holmes -v &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0.7.7&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Building native extensions. This could take a &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR:  Error installing charlock_holmes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR: Failed to build gem native extension.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current directory: /Users/will/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/charlock_holmes-0.7.7/ext/charlock_holmes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/2.6.1/bin/ruby -I /Users/will/.rbenv/versions/2.6.1/lib/ruby/2.6.0 -r ./siteconf20190213-34122-e636v8.rb extconf.rb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -licui18n... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; -licui18n... yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;checking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; unicode/ucnv.h... no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;***************************************************************************************
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*********** icu required &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;brew install icu4c or apt-get install libicu-dev&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; ***********
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;***************************************************************************************
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** extconf.rb failed ***
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Could not create Makefile due to some reason, probably lack of necessary
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;libraries and/or headers. Check the mkmf.log file &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; more details. You may
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;need configuration options.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Provided configuration options:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-opt-dir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-opt-dir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-opt-include
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-opt-include&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;opt-dir&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/include
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-opt-lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-opt-lib&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;opt-dir&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-make-prog
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-make-prog
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--srcdir&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--curdir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--ruby&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/Users/will/.rbenv/versions/2.6.1/bin/&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;RUBY_BASE_NAME&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-icu-dir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-icu-dir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-icu-include
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-icu-include&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;icu-dir&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/include
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-icu-lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-icu-lib&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;icu-dir&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;/lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-icui18nlib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-icui18nlib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--with-icui18nlib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--without-icui18nlib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;To see why this extension failed to compile, please check the mkmf.log which can be found here:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Users/will/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/charlock_holmes-0.7.7/mkmf.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;extconf failed, exit code &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Gem files will remain installed in /Users/will/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/charlock_holmes-0.7.7 &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; inspection.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Results logged to /Users/will/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/charlock_holmes-0.7.7/gem_make.out
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, make sure you have installed the required dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install xz icu4c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, install charlock_holmes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install charlock_holmes -v=0.7.7 -- --with-opt-dir=/usr/local/opt --with-opt-include=/usr/local/opt/icu4c/include --with-opt-lib=/usr/local/opt/icu4c/lib --with-cxxflags=-std=c++11
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
      
      <item>
      <title>Basic pasta sauce</title>
      <link>https://willj.net/posts/basic-pasta-sauce/</link>
      <pubDate>Tue, 14 Feb 2017 00:56:16 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/basic-pasta-sauce/</guid>
      <description>&lt;p&gt;Someone asked on Twitter how I made my pasta sauce, so here is the recipe! The base of my Pasta sauce is largely this recipe, except I mostly don&amp;rsquo;t add mozzarella:&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/eabecxMhJlE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;At it&amp;rsquo;s simplest I can make the whole thing for one person in 19 minutes, so it&amp;rsquo;s great for lunch.&lt;/p&gt;
&lt;h3 id=&#34;ingredients&#34;&gt;Ingredients&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;85g dried pasta per person (50g per child). You can use whatever you want, I prefer spaghetti.&lt;/li&gt;
&lt;li&gt;1 punnet of good tomatoes, about 225/250g (small ones, eg. baby plum, sunstream etc.)&lt;/li&gt;
&lt;li&gt;Small bunch of basil or parsely.&lt;/li&gt;
&lt;li&gt;Salt &amp;amp; Pepper&lt;/li&gt;
&lt;li&gt;1 clove of garlic&lt;/li&gt;
&lt;li&gt;1 chilli, I don&amp;rsquo;t de-seed&lt;/li&gt;
&lt;li&gt;Olive oil&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;method&#34;&gt;Method&lt;/h3&gt;
&lt;p&gt;To start, boil some water in a medium pan. Add a decent amount of salt. While the water is coming up to the boil prepare the other ingredients.&lt;/p&gt;
&lt;p&gt;First, chop the tomatoes, you can leave the skins on. I chop mine in half, I prefer the texture. It is also quicker. Finely chop the garlic and chilli. Roughly chop the basil or parsley.&lt;/p&gt;
&lt;p&gt;As soon as the water comes to the boil, add your pasta. Now heat some oil over a medium heat in a small frying pan. Add in the chilli and garlic. Make *really* sure not to burn the garlic. Before the garlic browns add in the tomatoes then a good pinch of salt. Stir around for a few seconds. Now add in some water. It&amp;rsquo;s really easy to add in too much, you want just enough to cover the base of the pan, any more and you&amp;rsquo;ll end up with soup. You can always add more if you need to.&lt;/p&gt;
&lt;p&gt;Next, add the basil or parsley. Stir through. When the pasta is al dente drain it retaining some of the cooking water and add to the sauce, stir around. Add pasta water if needed. You should still be able to work out what each of the individual parts of your sauce are made of. If you can&amp;rsquo;t you cooked it too long and/or added too much water.&lt;/p&gt;
&lt;p&gt;At this point you can stir in mozzarella, I mostly don&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Slap it on a plate, grate parmesan over it and eat it.&lt;/p&gt;
&lt;figure class=&#34;right&#34;&gt;&lt;img src=&#34;https://willj.net/posts/basic-pasta-sauce/images/z.jpg&#34;
    alt=&#34;Vegetables and bacon in a pan, the basis for a pasta sauce&#34;&gt;
&lt;/figure&gt;

&lt;h3 id=&#34;notes&#34;&gt;Notes&lt;/h3&gt;
&lt;p&gt;With practice I&amp;rsquo;ve got this down to 19 minutes for the simple version, you might be faster if you can boil water faster than me. Adding more stuff makes it slower obviously.&lt;/p&gt;
&lt;p&gt;Only get good tomatoes. They have to taste of something, if they don&amp;rsquo;t taste of anything your sauce will be crap. If you can&amp;rsquo;t get good fresh ones (or they have a gazillion air miles on them) use a &lt;em&gt;good&lt;/em&gt; tin. It&amp;rsquo;s not as good and doesn&amp;rsquo;t work as well with the parsley or mozzarella versions, but it&amp;rsquo;s better than the alternative.&lt;/p&gt;
&lt;p&gt;This sauce is great by itself, but you can add to it as you want. Some black pitted olives from a jar are great. If I&amp;rsquo;ve got other veg lying around, or more than one person eating I will add that too, depending on the density of the vegetable and how finely it is chopped depends when I add it. Chop it finer to cook it quicker. A good addition to bulk it up is a sweet pointed pepper &amp;amp; celery &lt;a href=&#34;https://en.wikipedia.org/wiki/Mirepoix_(cuisine)#Italian_soffritto&#34;&gt;soffritto&lt;/a&gt;. One pointed pepper and 2 celery sticks is about the right balance with one punnet of tomatoes. Fennel and black olive are great too. Just be careful not to overdo it. There&amp;rsquo;s enough sauce with just the tomatoes for one person, less is more when adding extra ingredients.&lt;/p&gt;
&lt;p&gt;If you do add more veg, try to keep the tomatoes per person ratio the same.&lt;/p&gt;
&lt;p&gt;In the photo above I went a bit crazy and added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sweet pointed pepper &amp;amp; celery soffritto&lt;/li&gt;
&lt;li&gt;1 small bulb of fennel, thinly sliced.&lt;/li&gt;
&lt;li&gt;Bacon*&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was really a bit too much.&lt;/p&gt;
&lt;p&gt;*Bacon! Aubergine is great for adding some a bulky umami flavour in-place of meat. Chop some aubergine into ~1cm cubes or strips, one handful should be enough, think proportional to the other ingredients. Put on some foil, sprinkle salt on, create a parcel (crimp the edges to keep the water in) and oven cook at ~180°C (?, experiment) until just soft then add to the sauce.&lt;/p&gt;
&lt;p&gt;I think that&amp;rsquo;s it! Nail the basic sauce then experiment on top of that and you&amp;rsquo;ve got a handy and versatile base!&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>The security of a system is as strong as it&#39;s weakest component</title>
      <link>https://willj.net/posts/the-security-of-a-system-is-as-strong-as-its-weakest-component/</link>
      <pubDate>Fri, 15 Apr 2016 12:47:57 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/the-security-of-a-system-is-as-strong-as-its-weakest-component/</guid>
      <description>&lt;p&gt;The padlock that had seized shut on my back gate was proving hard to remove, the hardened steel U was not yielding to my hacksaw. I noticed some rivets underneath that turned out to be soft steel. 10 minutes of sawing and I was in.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/the-security-of-a-system-is-as-strong-as-its-weakest-component/images/img_8951.jpg&#34;
    alt=&#34;CLoseup of a padlock with a Hardened steel U and body of layered steel plates&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Hardened steel U&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/the-security-of-a-system-is-as-strong-as-its-weakest-component/images/img_8950.jpg&#34;
    alt=&#34;Soft steel rivets on the bottom of the padlock&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Soft steel rivets on the bottom&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/the-security-of-a-system-is-as-strong-as-its-weakest-component/images/img_8953.jpg&#34;
    alt=&#34;The bottom plate of the padlock revealed, lock mechanism removed&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;After removing the rivets, hammering off the bottom plate&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/the-security-of-a-system-is-as-strong-as-its-weakest-component/images/img_8955.jpg&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The bottom plate revealed, lock mechanism removed&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/the-security-of-a-system-is-as-strong-as-its-weakest-component/images/img_8956.jpg&#34;
    alt=&#34;An open padlock&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Lock open!&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Random graph</title>
      <link>https://willj.net/posts/random-graph/</link>
      <pubDate>Fri, 25 Sep 2015 22:27:43 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/random-graph/</guid>
      <description>&lt;p&gt;Random graph, from playing around with &lt;a href=&#34;https://github.com/monora/rgl&#34;&gt;RGL&lt;/a&gt; in Ruby.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willjessop4.files.wordpress.com/2015/09/959tvax.jpg&#34;
    alt=&#34;A random graph&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;I like it, but it&amp;#39;s pointless&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>How to find if two nodes are connected in an RGL graph</title>
      <link>https://willj.net/posts/how-to-find-if-two-nodes-are-connected-in-an-rgl-graph/</link>
      <pubDate>Fri, 25 Sep 2015 16:39:53 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/how-to-find-if-two-nodes-are-connected-in-an-rgl-graph/</guid>
      <description>&lt;p&gt;Say you have a graph like this:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/how-to-find-if-two-nodes-are-connected-in-an-rgl-graph/images/graph.jpg&#34;
    alt=&#34;a simple graph&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;A simple graph&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;How do you find out if there is a path between any of the two nodes? By using a breadth-first search:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;require &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rgl/implicit&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;require &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rgl/traversal&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vertices &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;one&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;two&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;three&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;g &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;RGL&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ImplicitGraph&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;new &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;g&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  g&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;vertex_iterator { &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;b&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; vertices&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map{&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;v&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; b&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;call(v) } }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  g&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;adjacent_iterator { &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;x, b&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; b&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;call( vertices&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;(vertices&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;index(x) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;abs&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; ) }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  g&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;directed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;t &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; g&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;bfs_search_tree_from(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;one&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;puts t&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;has_vertex?(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;two&amp;#34;&lt;/span&gt;)   &lt;span style=&#34;color:#75715e&#34;&gt;# true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;puts t&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;has_vertex?(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;three&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;# false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
      
      <item>
      <title>I got my pan tilt servos working</title>
      <link>https://willj.net/posts/i-got-my-pan-tilt-servos-working/</link>
      <pubDate>Tue, 29 Jul 2014 22:59:02 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/i-got-my-pan-tilt-servos-working/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m making a simple camera gimbal and tonight I wired up the right analog stick on my xbox controller to control the pan/tilt servos:&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/C8RJzWzkW0c?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;Tomorrow I will print out a prototype gimbal structure.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Testing Github commit hook one liners</title>
      <link>https://willj.net/posts/testing-github-commit-hook-one-liners/</link>
      <pubDate>Mon, 09 Jun 2014 13:24:11 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/testing-github-commit-hook-one-liners/</guid>
      <description>&lt;p&gt;A couple of ruby one-liners for dumping out the content of a github commit hook payload:&lt;/p&gt;
&lt;p&gt;For hooks that use type &lt;strong&gt;application/json&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ruby -rpp -rjson -rsinatra -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;set :port, 8000; post &amp;#34;/*&amp;#34; do; pp JSON(request.body.read); end&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For hooks that use type &lt;strong&gt;application/x-www-form-urlencoded&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ruby -rpp -rjson -rsinatra -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;set :port, 8000; post &amp;#34;/*&amp;#34; do; pp JSON(params[:payload]); end&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
      
      <item>
      <title>AWS IAM Policy for allowing s3cmd to sync to an S3 bucket</title>
      <link>https://willj.net/posts/aws-iam-policy-for-allowing-s3cmd-to-sync-to-an-s3-bucket/</link>
      <pubDate>Fri, 18 Apr 2014 17:41:47 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/aws-iam-policy-for-allowing-s3cmd-to-sync-to-an-s3-bucket/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s a good idea to set an IAM access policy for anything that accesses AWS using your account details, I wanted to do this for s3cmd syncing a local directory to an s3 bucket. There are a &lt;a href=&#34;https://www.google.co.uk/search?q=s3cmd+iam+policy&amp;amp;oq=s3cmd+iam&amp;amp;aqs=chrome.0.69i59j69i57j69i60.4378j0j7&amp;amp;sourceid=chrome&amp;amp;es_sm=91&amp;amp;ie=UTF-8&#34;&gt;number of posts&lt;/a&gt; on setting up the IAM policy for s3cmd already but none of the examples worked for me, I got a 403 permission denied error when running the s3cmd sync command.&lt;/p&gt;
&lt;p&gt;After some digging it turns out that s3cmd now tries to set an ACL on the files it uploads, and this needs to be specifically allowed in the ACL. I&amp;rsquo;m guessing that it didn&amp;rsquo;t in the past, hence the now incorrect IAM advice. So here is the new working IAM policy, complete with the &lt;code&gt;s3:PutObjectAcl&lt;/code&gt; permission added:&lt;/p&gt;
&lt;p&gt;(See jrantil&amp;rsquo;s comment below on wether &lt;code&gt;s3:ListAllMyBuckets&lt;/code&gt; is needed in this instance)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2012-10-17&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Statement&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Sid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Stmt1397834652000&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Effect&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Action&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;s3:ListAllMyBuckets&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Resource&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;arn:aws:s3:::*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Sid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Stmt1397834745000&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Effect&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Action&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;s3:ListBucket&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;s3:PutObject&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;s3:PutObjectAcl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Resource&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;arn:aws:s3:::bucketname&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;arn:aws:s3:::bucketname/*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;update&#34;&gt;Update!&lt;/h2&gt;
&lt;p&gt;This post was imported from my original blog where there were comments, and these may be relevant to anyone finding this page now:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/aws-iam-policy-for-allowing-s3cmd-to-sync-to-an-s3-bucket/images/comments.png&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Comments on the original blog post&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Ping-Pong Press!</title>
      <link>https://willj.net/posts/ping-pong-press/</link>
      <pubDate>Mon, 16 Dec 2013 18:24:25 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/ping-pong-press/</guid>
      <description>&lt;p&gt;My robot was written about recently on the &lt;a href=&#34;http://www.raspberrypi.org/archives/5398&#34;&gt;Raspberry Pi foundation blog&lt;/a&gt; (now seemingly removed 😢, but &lt;a href=&#34;https://web.archive.org/web/20140330202855/https://www.raspberrypi.org/archives/5398&#34;&gt;still available on archive.org&lt;/a&gt;), and now on &lt;a href=&#34;http://www.pololu.com/blog/266/ping-pong-ball-collecting-robot-makes-appearance-at-rubyconf&#34;&gt;the Pololu blog&lt;/a&gt; too, the place I originally got my tracks from!&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Robot at RubyConf</title>
      <link>https://willj.net/posts/robot-at-rubyconf/</link>
      <pubDate>Mon, 09 Dec 2013 14:14:11 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/robot-at-rubyconf/</guid>
      <description>&lt;p&gt;I took my robot to &lt;a href=&#34;http://rubyconf.org/&#34;&gt;RubyConf&lt;/a&gt;. It&amp;rsquo;s not really Ruby related, but I figured it would go down like a robot at a programmers conference… So I took the robot apart, packed it away and headed to Miami:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2013/12/img_4472.jpg&#34;
    alt=&#34;A panorama of Miami, the view from my hotel balcony&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The view from my hotel balcony&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;First job, putting the robot back together again. I was happy it made it through security. It was the first time I&amp;rsquo;d flown with a small toolkit.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2013/12/img_4471.jpg&#34;
    alt=&#34;The robot dissasembled&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The robot laid bare&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2013/12/img_4482.jpg&#34;
    alt=&#34;Someone using an xbox controller to drive my robot&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;I was carrying the robot around most of the first day, people constantly asked to try it out&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It worked well on the shiny floor of the lobby. You can just about see the new 3d printed lifter arm:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2013/12/img_4486.jpg&#34;
    alt=&#34;A crowd of people watching someone use my robot&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The balls went everywhere&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/8RdkD-BATBE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;Totally coincidentally Ron Evans also did a great talk on &lt;a href=&#34;http://artoo.io/&#34;&gt;Artoo&lt;/a&gt; and the newly announced &lt;a href=&#34;http://gobot.io/&#34;&gt;Gobotio&lt;/a&gt;.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/mhXyNGX38mw?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;Programmers love robots!&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Prototype lifter arm</title>
      <link>https://willj.net/posts/prototype-lifter-arm/</link>
      <pubDate>Sat, 02 Nov 2013 22:04:05 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/prototype-lifter-arm/</guid>
      <description>&lt;p&gt;I added a prototype lifter arm to my robot yesterday. It needs re-doing (it&amp;rsquo;s unreliable and heavy) but it works for now.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using a new motor driver circuit for it as I burned out the SN754410 motor driver I was using, the lifter motor seems to peak briefly at about 1.5 amps when starting to lift the arm, and that&amp;rsquo;s out of the chips range. I stayed up late making a new motor control circuit with a L298N that can provide a lot more power.&lt;/p&gt;
&lt;p&gt;Here is the robot picking up 12 ping-pong balls. I was driving, Morwenna was filming:&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/doxEBi1UjLg?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;Here is the same run seen through the on-board camera. Almost all of the run was done watching the live feed rather than watching the robot itself:&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/T1NwjBEUjio?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;Here is the paper strip-board design for the L298N circuit.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2013/11/img_4442.jpg&#34;
    alt=&#34;Designing tHe motor driver circuit for stripboard&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Designing tHe motor driver circuit for stripboard&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Testing the circuit out on breadboard:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2013/11/img_4440.jpg&#34;
    alt=&#34;A mess of wires and breadboard and stripboard&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Wire everywhere, as often happens when I&amp;#39;m doing electronics projects&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2013/11/img_4441.jpg&#34;
    alt=&#34;A finished circuit on stripbord&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The finished circuit. You can see it bolted to the back of the robot in the video.&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>First robot remote driving test</title>
      <link>https://willj.net/posts/first-robot-remote-driving-test/</link>
      <pubDate>Fri, 01 Nov 2013 02:16:09 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/first-robot-remote-driving-test/</guid>
      <description>&lt;p&gt;I programmed some remote control software using a Golang receiving program on the robot and a ruby control client using my &lt;a href=&#34;https://github.com/wjessop/gamepad&#34;&gt;gamepad ruby gem&lt;/a&gt; and an Xbox 1 controller. It worked OK. It was a bit jerky, there&amp;rsquo;s no PWM so no acceleration, it&amp;rsquo;s either go or stop; anything not totally rigid on the robot wobbles. Also the position of the camera doesn&amp;rsquo;t show enough of the robot so it&amp;rsquo;s hard to get a real idea of where the robot is.&lt;/p&gt;
&lt;p&gt;I was filming, the robot was being controlled my my wife, Morwenna, from upstairs.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/4YYC7bCiRTI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;The robot is also prone to shed a track if the &amp;ldquo;half turn&amp;rdquo; is used too much, that is one track forwards or backwards, the other one stationary. I can fix this in software if I can work out a way to do PWM on the robot that doesn&amp;rsquo;t run the Raspberry Pi CPU.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Rejects and prototypes</title>
      <link>https://willj.net/posts/rejects-and-prototypes/</link>
      <pubDate>Thu, 31 Oct 2013 13:25:19 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/rejects-and-prototypes/</guid>
      <description>&lt;p&gt;Prototypes and rejects from the 3d printer. All part of the design process for my robot:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/rejects-and-prototypes/images/img_4436.jpg&#34;
    alt=&#34;Rejected and prototype 3D printed robot componenets&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Rejected and prototype 3D printed componenets&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>New robot base design and completed prototype arm assembly</title>
      <link>https://willj.net/posts/new-robot-base-design-and-completed-prototype-arm-assembly/</link>
      <pubDate>Thu, 31 Oct 2013 13:16:49 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/new-robot-base-design-and-completed-prototype-arm-assembly/</guid>
      <description>&lt;p&gt;I spent all day at &lt;a href=&#34;http://hacman.org.uk/&#34;&gt;hacman&lt;/a&gt; Tuesday and Wednesday printing and tweaking robot parts. I put it all together when I got home. This is the front, the lifter arm has holes to allow me to screw in different attachments, I&amp;rsquo;ve still not designed that part of the robot yet:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/new-robot-base-design-and-completed-prototype-arm-assembly/images/img_4432.jpg&#34;
    alt=&#34;The robot, mostly assembled&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The robot, mostly assembled&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Here is the back view, you can see the lifter arm gear housing (the curved structure) and the motor that drives it, also the battery (underneath the ball hopper)&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/new-robot-base-design-and-completed-prototype-arm-assembly/images/img_4433.jpg&#34;
    alt=&#34;The rear of the robot with the hopper in place&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The rear of the robot with the hopper in place&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The lifter arm gear system looking through where the hopper would be:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/new-robot-base-design-and-completed-prototype-arm-assembly/images/img_4434.jpg&#34;
    alt=&#34;The robot without the hopper in place&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The robot without the hopper in place&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I need to design an attachment for the end of the lifter arm. Here I&amp;rsquo;ve created a simple one using meccano. It&amp;rsquo;s too heavy, the bolts catch on the floor and it dumps the ping-pong balls short of the hopper. Other than that it&amp;rsquo;s perfect. You can see the camera with capped lens that I&amp;rsquo;ve just wedged into the structure temporarily:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/new-robot-base-design-and-completed-prototype-arm-assembly/images/img_44351.jpg&#34;
    alt=&#34;A prototype lifter arm made from meccano, attached to the robot&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;A prototype lifter arm made from Meccano&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Next-up&lt;/strong&gt;: better lifter attachment design, a couple of re-prints with tweaks and some software.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Testing the new battery &#43; lifter arm circuit</title>
      <link>https://willj.net/posts/testing-the-new-battery-and-lifter-arm-circuit/</link>
      <pubDate>Mon, 28 Oct 2013 23:02:01 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/testing-the-new-battery-and-lifter-arm-circuit/</guid>
      <description>&lt;p&gt;First test of the Raspberry Pi running off battery power with no external supply at all. In the picture the 5000mAh battery is the object at the back with &amp;ldquo;5000&amp;rdquo; written on it. My multimeter is measuring the voltage output. One of the Raspberry Pi (the thing with the red light on it) output pins is connected through the MotorPiTX board (the yellow circuit board on-top of the Raspberry Pi) to the breadboard.&lt;/p&gt;
&lt;p&gt;The breadboard contains two circuits, the top-right cluster of components is the circuit that turns the output of the Raspberry Pi into something relevant to the motor driver in the bottom left, the bottom left cluster of components is the motor driver itself.&lt;/p&gt;
&lt;p&gt;The Pi is pulsing the output causing the motor driver to spin the motor. The micro-switch just on the very bottom of the picture is one of the limit switches for the ball lifter arm.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/testing-the-new-battery-and-lifter-arm-circuit/images/img_4418.jpg&#34;
    alt=&#34;A curcuit under test with a multimeter&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;A relatively tidy electronics bench for once&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>An assembled ping-pong robot hopper</title>
      <link>https://willj.net/posts/an-assembled-hopper/</link>
      <pubDate>Thu, 24 Oct 2013 01:27:44 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/an-assembled-hopper/</guid>
      <description>&lt;p&gt;Today I printed out and glued together the first iteration of the ping-pong ball hopper that takes up most of the space of the robot.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/an-assembled-hopper/images/img_4405.jpg&#34;
    alt=&#34;The assembled hopper&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The assembled hopper&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Full of ping-pong balls, I can get 12-14 in without packing them manually. That seems like enough for now, but a larger hopper would be good.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/an-assembled-hopper/images/img_4406.jpg&#34;
    alt=&#34;The hopper loaded with ping-pong balls&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The hopper loaded with ping-pong balls&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Mounted on the robot. You can see the completed camera mount and Raspberry Pi mounted on the side in the foreground:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/an-assembled-hopper/images/img_4407.jpg&#34;
    alt=&#34;The ping-pong ball hopper mounted on the robot&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The ping-pong ball hopper mounted on the robot&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/an-assembled-hopper/images/img_4408.jpg&#34;
    alt=&#34;The reverse angle&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The reverse angle&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Testing new motor mounts</title>
      <link>https://willj.net/posts/testing-new-motor-mounts/</link>
      <pubDate>Thu, 24 Oct 2013 01:22:00 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/testing-new-motor-mounts/</guid>
      <description>&lt;p&gt;I needed to re-design the motor mounts on the robot base, they didn&amp;rsquo;t hold the motors securely enough and tended to shift around.&lt;/p&gt;
&lt;p&gt;The new mounts are better fitting and include a small wedge that fits between one of the gearbox plates where there are no cogs.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/testing-new-motor-mounts/images/img_4404.jpg&#34;
    alt=&#34;Two small motors with in-built gearboxes in motor mounts&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;You can see the small gearboxes built in to the motors&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/testing-new-motor-mounts/images/img_4403.jpg&#34;
    alt=&#34;Two motors fully encased in the motor mounts&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The new motor mounts are a snug fit&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;One of the great things about 3d printing is being able to pull out part of a design and iterate over in isolation, then when you&amp;rsquo;re done incorporate it back into your main design.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Raspberry Pi camera mount &#43; lens holder</title>
      <link>https://willj.net/posts/raspberry-pi-camera-mount-and-lens-holder/</link>
      <pubDate>Thu, 24 Oct 2013 01:15:37 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/raspberry-pi-camera-mount-and-lens-holder/</guid>
      <description>&lt;p&gt;I printed out the front half of my Raspberry Pi camera module mount. It serves two purposes, providing a way of mounting the camera on my robot, and giving me a place to attach the wide-angle lens I&amp;rsquo;d bought earlier.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/raspberry-pi-camera-mount-and-lens-holder/images/img_4394.jpg&#34;
    alt=&#34;Raspberry pi camera holder&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The new Raspberry pi camera holder&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/raspberry-pi-camera-mount-and-lens-holder/images/img_4396.jpg&#34;
    alt=&#34;Raspberry pi camera holder, rear, showing a circuit board&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The new Raspberry pi camera holder rear view&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>New Pi mount, and testing the power requirements</title>
      <link>https://willj.net/posts/new-pi-mount-and-testing-the-power-requirements/</link>
      <pubDate>Sun, 20 Oct 2013 00:06:46 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/new-pi-mount-and-testing-the-power-requirements/</guid>
      <description>&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/new-pi-mount-and-testing-the-power-requirements/images/img_4390.jpg&#34;
    alt=&#34;Testing the robot power requirements&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Testing the robot power requirements&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Before I pick a battery I need to know what power requirements my robot is going to have so I took it into the &lt;a href=&#34;http://hacman.org.uk/&#34;&gt;hackspace&lt;/a&gt; to test. I hooked it up to one of the power supplies then ran all the systems, so Streaming video off the Raspberry Pi over wireless whilst running the motors. I weight it down with a large motor (the big black thing) and then provided resistance, it peaks at about 1.6 amps.&lt;/p&gt;
&lt;p&gt;In the video you can also see the new side mounted Raspberry Pi and the base of the ping-pong ball hopper.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/rA89dFa6OmU?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;Detail view of the side mounted Raspberry Pi and the base of the ping-pong ball hopper:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/new-pi-mount-and-testing-the-power-requirements/images/img_4392.jpg&#34;
    alt=&#34;Raspberry Pi mount and ping-pong ball hopper base&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Raspberry Pi mount and ping-pong ball hopper base&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Lenses</title>
      <link>https://willj.net/posts/lenses/</link>
      <pubDate>Fri, 18 Oct 2013 16:17:20 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/lenses/</guid>
      <description>&lt;p&gt;The Raspberry Pi camera doesn&amp;rsquo;t have a field of view that is wide enough for my robot, I&amp;rsquo;d have to mount it really far from my robot to see enough context to make it drivable so I&amp;rsquo;ve bought some wide angle iPhone lenses to try out.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/lenses/images/img_4386.jpg&#34;
    alt=&#34;Wide-angle and fish-eye lenses&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Wide-angle and fish-eye lenses&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Here&amp;rsquo;s a photo taken using the fish-eye lens held up to my iPhone:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/lenses/images/img_4388.jpg&#34;
    alt=&#34;The view through the fish-eye lens&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The view through the fish-eye lens&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>First prototype robot base</title>
      <link>https://willj.net/posts/prototype-robot-base/</link>
      <pubDate>Mon, 30 Sep 2013 20:08:56 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/prototype-robot-base/</guid>
      <description>&lt;p&gt;The robot base design from my previous post printed OK. Here it is printing:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/prototype-robot-base/images/img_4320.jpg&#34;
    alt=&#34;A 3d printer printing on a glass sheet&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Robot base 3D printing&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The finished print. The two small separate objects are the motor covers:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/prototype-robot-base/images/img_4322.jpg&#34;
    alt=&#34;A completed 3d print&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Completed robot base print&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The assembled robot, including Raspberry Pi and MotorPiTX:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/prototype-robot-base/images/img_4330.jpg&#34;
    alt=&#34;An assembled robot&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Assembled robot base&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The underside of the robot:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/prototype-robot-base/images/img_4332.jpg&#34;
    alt=&#34;The underside of a robot&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Even robots have a bottom&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>OpenSCAD robot base design</title>
      <link>https://willj.net/posts/openscad-robot-base-design/</link>
      <pubDate>Tue, 24 Sep 2013 01:23:15 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/openscad-robot-base-design/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve re-designed a prototype robot mount in OpenSCAD as Sketchup wasn&amp;rsquo;t up to the job. It took a while, you have to program the model in a text editor so there&amp;rsquo;s lots of trial and error. Will have to wait to print it to see if this design will work.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/openscad-robot-base-design/images/screen-shot-2013-09-24-at-02-18-33.png&#34;
    alt=&#34;A CAD model of a small part of the base of my robot&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Prototype robot base designed in OpenSCAD&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve made some improvements over the &lt;a href=&#34;https://willj.net/posts/designing-a-track-mount&#34;&gt;original design&lt;/a&gt;, most notably thicker side walls and motor mounts, more accurate measurements and added the cross-pieces with a Raspberry Pi mount. Here&amp;rsquo;s the original Sketchup design for comparison:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/openscad-robot-base-design/images/screen-shot-2013-09-22-at-20-27-41.png&#34;
    alt=&#34;The same robot base as before but in Sketchup&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Robot base designed in Sketchup&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Sketchup was great, really easy to use, the only problem was that it seemed to create invalid model files.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Trying out the prototype caterpillar track mount</title>
      <link>https://willj.net/posts/trying-out-the-prototype-caterpillar-track-mount/</link>
      <pubDate>Mon, 23 Sep 2013 18:09:32 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/trying-out-the-prototype-caterpillar-track-mount/</guid>
      <description>&lt;p&gt;It works, but it needs more refinement.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/trying-out-the-prototype-caterpillar-track-mount/images/img_4296.jpg&#34;
    alt=&#34;A Pololu track and motor in a prototype mount&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Testing the new motor mount&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Printing out a test caterpillar track and motor mount</title>
      <link>https://willj.net/posts/printing-out-a-test-caterpillar-track-and-motor-mount/</link>
      <pubDate>Mon, 23 Sep 2013 14:38:44 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/printing-out-a-test-caterpillar-track-and-motor-mount/</guid>
      <description>&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/-1ye-TLipiY?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/printing-out-a-test-caterpillar-track-and-motor-mount/images/img_4289.jpg&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Printing a motor / caterpillar track mount detail&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/printing-out-a-test-caterpillar-track-and-motor-mount/images/img_4290.jpg&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The 3d printer at work&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Designing a track mount</title>
      <link>https://willj.net/posts/designing-a-track-mount/</link>
      <pubDate>Sat, 21 Sep 2013 22:42:44 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/designing-a-track-mount/</guid>
      <description>&lt;p&gt;Designing a track mount for my pololu caterpillar tracks. Sketchup is trying very hard to prevent me.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/designing-a-track-mount/images/screen-shot-2013-09-21-at-23-37-18.png&#34;
    alt=&#34;Screengrab of an in-progress design for a track mount&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Pololu track mount design in progress&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Secret project - MotorPiTX motor board</title>
      <link>https://willj.net/posts/secret-project-motorpitx-motor-board/</link>
      <pubDate>Sun, 08 Sep 2013 00:51:32 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/secret-project-motorpitx-motor-board/</guid>
      <description>&lt;p&gt;I soldered together my MotorPiTX motor controller today and fitted it to the robot:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/secret-project-motorpitx-motor-board/images/img_4256.jpg&#34;
    alt=&#34;A prototype robot with a MotorPiTX board on top of a Raspberry Pi&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The robot with MotorPiTX board&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s a hell of a lot neater than my original effort, and only trails one wire. It goes forwards &lt;em&gt;and&lt;/em&gt; backwards now too. To the left of the blue relay near the top you can see my homemade heatsink attached to the voltage regulator:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/secret-project-motorpitx-motor-board/images/img_4257.jpg&#34;
    alt=&#34;Closeup of a heatsink made of meccano parts&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Pro-spec heatsink&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The robot in action, being driven by a Go program on the Raspberry Pi:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=hIabB-AURT0&#34;&gt;http://www.youtube.com/watch?v=hIabB-AURT0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next up, getting the camera working, and figuring out a better power supply/battery.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Secret project</title>
      <link>https://willj.net/posts/secret-project/</link>
      <pubDate>Sat, 07 Sep 2013 12:41:02 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/secret-project/</guid>
      <description>&lt;figure class=&#34;right&#34;&gt;&lt;img src=&#34;https://willj.net/posts/secret-project/images/41c6bjctp2l1.jpg&#34;
    alt=&#34;A very small motor with an in-built gearbox&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;One of my new motors. It&amp;#39;s about 10mm in diameter&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve started work on a top-secret project. I can&amp;rsquo;t really hide the fact that it&amp;rsquo;s going to be a robot, but I&amp;rsquo;m not going to say what it is, at least not just yet.&lt;/p&gt;
&lt;p&gt;So, last night I was designing a 3d printed mount for the &lt;a href=&#34;http://www.amazon.co.uk/gp/product/B008OAYP8Q/ref=as_li_ss_tl?ie=UTF8&amp;amp;camp=1634&amp;amp;creative=19450&amp;amp;creativeASIN=B008OAYP8Q&amp;amp;linkCode=as2&amp;amp;tag=will_j-21&#34; title=&#34;3-6V motors&#34;&gt;tiny 3-6V motors&lt;/a&gt; I bought and I started to wonder if I could cobble something together using my old technic lego. I dug out the lego, but on top of that was my dusty old meccano set, even better!&lt;/p&gt;
&lt;p&gt;WIthin a short amount of time I had some motor mounts and a frame made, including tensioning springs for the caterpillar tracks. All that was left was to take it for a spin. I hooked it up to my Raspberry Pi via my Custard Pi breakout board, a &lt;a href=&#34;https://simple.m.wikipedia.org/wiki/File:ULN2803A_Transistor_Array.jpg&#34;&gt;ULN2803A&lt;/a&gt; and a custom voltage regulator circuit.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/secret-project/images/img_4248.jpg&#34;
    alt=&#34;A very small motor with an in-built gearbox&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Motor mount&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Seeing if it drives in a straight line:&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/JrhgSdsNkCM?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;Hooked up to the Raspberry Pi, controlled by microswitches. You can see the top of the Custard Pi poking out over the mess of wires that is my breadboard and the cheap wireless dongle/antenna I got from eBay. The voltage regulator circuit makes an appearance being dragged along behind:&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/Op8CD11w8OQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/secret-project/images/img_4247.jpg&#34;
    alt=&#34;A PCB with no components on it and a bag of componenets&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;MotorPiTX kit&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Right now it only goes forwards because I didn&amp;rsquo;t have the circuitry for anything else, but I got my MotorPiTX in the mail this morning so that will change soon.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>go-piglow, a lib for controlling the piglow in Golang</title>
      <link>https://willj.net/posts/go-piglow-a-lib-for-controlling-the-piglow-in-golang/</link>
      <pubDate>Tue, 03 Sep 2013 23:26:43 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/go-piglow-a-lib-for-controlling-the-piglow-in-golang/</guid>
      <description>&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/go-piglow-a-lib-for-controlling-the-piglow-in-golang/images/piglow.jpg&#34;
    alt=&#34;A Piglow Raspberry pi board lit up&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;A Piglow glowing&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;A few days ago I got a &lt;a href=&#34;http://shop.pimoroni.com/products/piglow&#34; title=&#34;Piglow&#34;&gt;Piglow&lt;/a&gt;. It&amp;rsquo;s a fairly useless but fun addon board for the Raspberry Pi that has 18 individual user controllable LEDs arranged in Arms/Legs/Tentacles (whatever you want to call them).&lt;/p&gt;
&lt;p&gt;There are example programs out there to control the LEDs, but they are all in Python, and on my Pi they are all fairly slow so I wrote my own lib for Go: &lt;a href=&#34;https://github.com/wjessop/go-piglow&#34;&gt;https://github.com/wjessop/go-piglow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The API is fairly strigthtforward, this sample program just turns on and off some of the LEDS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/wjessop/go-piglow&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;piglow&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Piglow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Create a new Piglow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;piglow&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewPiglow&lt;/span&gt;(); &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Couldn&amp;#39;t create a Piglow: &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetLED&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// Set LED 0 to 255 (max brightness)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetLED&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// Set LED 1 to half brightness&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Apply&lt;/span&gt;(); &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; { &lt;span style=&#34;color:#75715e&#34;&gt;// Apply the changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Couldn&amp;#39;t apply changes: &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The lib API allows for controlling individual LEDs, the colour rings, the tentacles, or to display a value bar-graph style on each tentacle.&lt;/p&gt;
&lt;p&gt;I wrote some more complex example programs to go with the lib to demo these capabilities. A simple program to flash the LEDs, a CPU meter that displays 1, 5 and 15 minute load average on each of the tentacles, and the most fun, a disco program, here is me demonstrating them:&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/1EmJIwzhJwQ?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

&lt;p&gt;Right now i&amp;rsquo;m running &lt;a href=&#34;https://github.com/wjessop/piglow-fader&#34; title=&#34;piglow-fader&#34;&gt;this program&lt;/a&gt; on my Pi to slowly fade between the colour rings.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Creating BERT dicts in Go</title>
      <link>https://willj.net/posts/creating-bert-dicts-in-go/</link>
      <pubDate>Sun, 10 Feb 2013 02:09:06 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/creating-bert-dicts-in-go/</guid>
      <description>&lt;p&gt;I’ve been learning Go recently and have written a program to connect to an existing service (written in Ruby) that sends and receives messages serialised as &lt;a href=&#34;http://bert-rpc.org/&#34;&gt;BERT&lt;/a&gt; terms.&lt;/p&gt;
&lt;p&gt;I’m posting this partly because I had quite a lot of fun figuring it out and partly to document creating BERT dicts in Go should anyone else need to do this in the future and hit the same issues I did.&lt;/p&gt;
&lt;h2 id=&#34;why-bert&#34;&gt;Why BERT?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m a big fan of BERT. It’s compact, flexible, and there are good libs available for serialisation/de-serialisation. So far I’ve exclusively been using the &lt;a href=&#34;https://github.com/mojombo/bert&#34;&gt;bert gem&lt;/a&gt; (written by Tom Preston-Werner, author of the BERT spec).&lt;/p&gt;
&lt;h2 id=&#34;creating-bert-dicts&#34;&gt;Creating BERT dicts&lt;/h2&gt;
&lt;p&gt;One of the great features of BERT is the complex types it supports, including dicts. The equivalent to a dict in Ruby would be a hash, in Go a map. They are really simple to create in Ruby:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;require &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;bert&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;BERT&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;val&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x83&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x03&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;bertd&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;dictl&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x01&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x02&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;m&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x03&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;keym&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x03&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;valj&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can pull this apart and see exactly what the bert gem did to our data. Let&amp;rsquo;s dump the string to an array of 8-bit unsigned integers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;BERT&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;val&amp;#34;&lt;/span&gt;})&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;unpack(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C*&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;131&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;98&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;114&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;105&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;109&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;107&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;121&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;109&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;118&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;97&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;106&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It’s hard to see exactly what happened, but with the BERT docs and the &lt;a href=&#34;http://erlang.org/doc/apps/erts/erl_ext_dist.html&#34;&gt;erlang External Term Format docs&lt;/a&gt; we can see how the hash got encoded.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;magic| tuple |  atom   |       bert     |            |    dict        |  list 1 elem    |      list      |   atom  |      key      |   atom  |      |  val       | nil | nil
131, 104, 3, 100, 0, 4, 98, 101, 114, 116, 100, 0, 4, 100, 105, 99, 116, 108, 0, 0, 0, 1, 108, 0, 0, 0, 2, 100, 0, 3, 107, 101, 121, 100, 0, 3,       118, 97, 108, 106, 106
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the formatting of that breakdown is messed up &lt;a href=&#34;https://gist.github.com/wjessop/4747914/raw/a7cea5f08b87add27c677145fa49815ed0c98faf/gistfile1.txt&#34;&gt;here’s a raw gist&lt;/a&gt; that may be clearer.&lt;/p&gt;
&lt;p&gt;What you can see here are what the bytes represent (you can see the breakdown of each data type on the External Term Format &lt;a href=&#34;http://erlang.org/doc/apps/erts/erl_ext_dist.html&#34;&gt;docs&lt;/a&gt;). This is great, but why write a blog post just about dicts? Well, they’re easy to create in Ruby:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;BERT&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode(&lt;span style=&#34;color:#e6db74&#34;&gt;:complex&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:data&lt;/span&gt;, {&lt;span style=&#34;color:#e6db74&#34;&gt;:structures&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;are easy to serialise&amp;#34;&lt;/span&gt;}&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x83&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x03&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;bertd&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;dictl&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x01&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x02&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\a&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;complexh&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x03&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;bertd&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;dictl&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x01&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x02&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;m&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x03&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;keyl&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x02&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;datah&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x03&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;bertd&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x04&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;dictl&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x01&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x02&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;structuresm&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\x00\x00\x00\x15&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;are easy to serialisejjjj&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;but it’s not so obvious in Go, and I hit some issues when trying to create them.&lt;/p&gt;
&lt;h2 id=&#34;serialising-to-bert-in-golang&#34;&gt;Serialising to BERT in Golang&lt;/h2&gt;
&lt;p&gt;Serialising data to BERT/BERP in Go is pretty easy for simple cases using the &lt;a href=&#34;https://github.com/sethwklein/gobert&#34;&gt;gobert&lt;/a&gt; lib:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/sethwklein/gobert&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt; = new(&lt;span style=&#34;color:#a6e22e&#34;&gt;bytes&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MarshalResponse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Bytes&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%d &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives us:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 7 131 100 0 3 102 111 111
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we run that through the Ruby lib decoder we get:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BERT&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;decode(&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;131&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;102&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;111&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;111&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;].&lt;/span&gt;pack(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C*&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(The Ruby bert lib decodes atoms to symbols).&lt;/p&gt;
&lt;h2 id=&#34;serialising-to-bert-dicts-in-golang&#34;&gt;Serialising to BERT dicts in Golang&lt;/h2&gt;
&lt;p&gt;However, there is a little more effort involved serialising more complex data structures, in particular dicts, as I found out.&lt;/p&gt;
&lt;p&gt;You might have thought that you could just pass in a map:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/sethwklein/gobert&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;val1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;val2&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt; = new(&lt;span style=&#34;color:#a6e22e&#34;&gt;bytes&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MarshalResponse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Bytes&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%d &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We get the output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 1 131
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that doesn’t work. What you end up with is a one byte long BERP. It seems that gobert doesn’t automatically serialise maps. No problem, we’ll build one up manually. A quick look at the BERT documentation shows the format of a dict:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Dictionaries (hash tables) are expressed via an array of 2-tuples representing the key/value pairs. The KeysAndValues array is mandatory, such that an empty dict is expressed as {bert, dict, []}. Keys and values may be any term. For example, {bert, dict, [{name, &amp;laquo;“Tom”&amp;raquo;}, {age, 30}]}.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;So let&amp;rsquo;s create this special structure manually.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/sethwklein/gobert&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;message1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;val1&amp;#34;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;message2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;val3&amp;#34;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;keys_and_values&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;message1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;message2&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;dict&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;BertAtom&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dict&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;keys_and_values&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt; = new(&lt;span style=&#34;color:#a6e22e&#34;&gt;bytes&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MarshalResponse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;dict&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Bytes&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%d &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 51 131 104 3 100 0 4 98 101 114 116 100 0 4 100 105 99 116 104 2 104 2 100 0 4 107 101 121 49 100 0 4 118 97 108 49 104 2 100 0 4 107 101 121 50 100 0 4 118 97 108 51
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It looks better, but it doesn’t decode, using Ruby:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BERT&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;decode(&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;131&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;98&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;114&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;105&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;107&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;121&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;118&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;97&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;107&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;121&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;118&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;97&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;51&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;].&lt;/span&gt;pack(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C*&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;TypeError&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;Invalid&lt;/span&gt; dict spec, &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; an erlang list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We’re still missing something. Let&amp;rsquo;s compare the output of the Ruby bert lib to the output of gobert for the same data structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BERT&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode({&lt;span style=&#34;color:#e6db74&#34;&gt;:key1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:val1&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:key2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;:val2&lt;/span&gt;})&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;unpack(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C*&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;131&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;98&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;114&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;105&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;107&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;121&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;118&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;97&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;107&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;121&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;118&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;97&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;106&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We’re definitely missing some data in the gobert output.&lt;/p&gt;
&lt;p&gt;If you follow along the byte sequences you can see that they start off the same until the 18th byte. In the Ruby output this is ‘108’, or LIST_EXT. In the gobert output it’s 104, a SMALL_TUPLE_EXT. We can see where this difference happens in encode.go in the gobert lib (in the writeTag func):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reflect&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Slice&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;writeSmallTuple&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reflect&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Array&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;writeList&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s decode the BERT data to see where the diversion happens in the underlying data structures:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;magic| tuple  |  atom   |       bert       |   atom   |    dict
  131, 104, 3, 100, 0, 4, 98, 101, 114, 116, 100, 0, 4, 100, 105, 99, 116
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see that the “bert” and “dict” atoms are encoded the same, but the keys_and_values array is getting encoded as a SMALL_TUPLE_EXT by gobert when we wanted a LIST_EXT. If we look back at the gobert code we can see that the decision to use SMALL_TUPLE_EXT over LIST_EXT is dependent on a slice or array being present. We can use the go “reflect” package to look at the arrays/slices we are creating and see what they are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reflect&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/sethwklein/gobert&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;array&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;array_val&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reflect&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ValueOf&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;array&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;slice_val&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reflect&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ValueOf&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;array is a: %v\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;array_val&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Kind&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;slice is a: %v\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;slice_val&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Kind&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;array is a: array
slice is a: slice
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;the-fix&#34;&gt;The fix&lt;/h2&gt;
&lt;p&gt;So, in order to fix our data structure to get gobert to correctly encode the dict we need to change the keys_and_values slice to an array:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/sethwklein/gobert&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;message1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;val1&amp;#34;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;message2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;val3&amp;#34;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;keys_and_values&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;message1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;message2&lt;/span&gt;} &lt;span style=&#34;color:#75715e&#34;&gt;// Now an array&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;dict&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Term&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;BertAtom&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atom&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dict&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;keys_and_values&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt; = new(&lt;span style=&#34;color:#a6e22e&#34;&gt;bytes&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;bert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MarshalResponse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;dict&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Bytes&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%d &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 55 131 104 3 100 0 4 98 101 114 116 100 0 4 100 105 99 116 108 0 0 0 2 104 2 100 0 4 107 101 121 49 100 0 4 118 97 108 49 104 2 100 0 4 107 101 121 50 100 0 4 118 97 108 51 106
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But more importantly, can we decode the data we encoded?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BERT&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;decode(&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;131&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;98&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;114&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;105&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;116&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;107&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;121&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;118&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;97&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;104&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;107&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;121&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;118&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;97&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;51&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;106&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;].&lt;/span&gt;pack(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C*&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;:key1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:val1&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;:key2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:val3&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes!&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Creating animated gifs with imagemagick</title>
      <link>https://willj.net/posts/creating-animated-gifs-with-imagemagick/</link>
      <pubDate>Tue, 24 Apr 2012 10:49:42 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/creating-animated-gifs-with-imagemagick/</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://willj.net/posts/railsberry-animated-gifs&#34; title=&#34;Railsberry animated gifs&#34;&gt;my last post&lt;/a&gt; I linked to some animated gifs I made on my mac. It&amp;rsquo;s pretty easy if you have imagemagick installed.&lt;/p&gt;
&lt;p&gt;Simply get a bunch of images together and use the convert command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;convert -resize 900x -loop 0 -delay 10 DSC_8264.JPG DSC_8265.JPG DSC_8266.JPG DSC_8267.JPG DSC_8268.JPG DSC_8269.JPG DSC_8270.JPG jon_walk.gif
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last argument is the output filename. The options should be self explanatory, but you can check them up in the man page if you want to tweak the values.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Railsberry animated gifs</title>
      <link>https://willj.net/posts/railsberry-animated-gifs/</link>
      <pubDate>Mon, 23 Apr 2012 16:05:30 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/railsberry-animated-gifs/</guid>
      <description>&lt;p&gt;I put up some &lt;a href=&#34;http://www.flickr.com/photos/will_j/sets/72157629881298443/&#34; title=&#34;Railsberry&#34;&gt;photos of Railsberry here&lt;/a&gt;, but Flickr doesn&amp;rsquo;t work with animated gifs, so here they are. Click the images to get the animated versions.&lt;/p&gt;
&lt;h4 id=&#34;riding-the-railsberry-unicorn&#34;&gt;Riding the Railsberry Unicorn:&lt;/h4&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/railsberry-animated-gifs/images/riding_unicorn.gif&#34;
    alt=&#34;A woman riding someone in a unicorn mask&#34;&gt;
&lt;/figure&gt;

&lt;h4 id=&#34;jon-leighton-getting-closer&#34;&gt;Jon Leighton getting closer:&lt;/h4&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/railsberry-animated-gifs/images/jon_walk.gif&#34;
    alt=&#34;Jon Leighton getting getting progressively closer to the camera, stop motion style&#34;&gt;
&lt;/figure&gt;

&lt;h4 id=&#34;josh-kalderimis-misbehaving&#34;&gt;Josh Kalderimis misbehaving:&lt;/h4&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/railsberry-animated-gifs/images/jk.gif&#34;
    alt=&#34;A man doing something like a jazz hands pose&#34;&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Paula Deen riding things</title>
      <link>https://willj.net/posts/paula-deen-riding-things/</link>
      <pubDate>Thu, 02 Feb 2012 22:00:10 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/paula-deen-riding-things/</guid>
      <description>&lt;p&gt;I made some Paula Deen riding… pictures. Because I can.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/paula-deen-riding-things/images/paula-deen-sausuage.jpeg&#34;
    alt=&#34;Paula deen riding a sausage&#34;&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/paula-deen-riding-things/images/paula-deen-riding-kitten.jpeg&#34;
    alt=&#34;Paula deen riding a kitten&#34;&gt;
&lt;/figure&gt;

&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/paula-deen-riding-things/images/original.jpeg&#34;
    alt=&#34;Paula deen riding a science cat&#34;&gt;
&lt;/figure&gt;

</description>
    </item>
    
      
      <item>
      <title>Testing http over socket connections with socat</title>
      <link>https://willj.net/posts/testing-http-over-socket-connections-with-socat/</link>
      <pubDate>Fri, 02 Dec 2011 22:00:55 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/testing-http-over-socket-connections-with-socat/</guid>
      <description>&lt;p&gt;Sometimes I need to test an http server that is listening on a unix socket. It&amp;rsquo;s really easy to do this using socat, but the socat man page is pretty long. Here it is for anyone who needs it in the future, and me when I inevitably forget.&lt;/p&gt;
&lt;p&gt;In this case the server is unicorn, but this will work for any http server listening on a socket, for instance thin. The lines beginning with &amp;ldquo;&amp;ndash;&amp;gt;&amp;rdquo; are lines I typed (the 4 lines at the start), remove the &amp;ldquo;&amp;ndash;&amp;gt;&amp;rdquo; when you try this.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ socat - UNIX-CONNECT:/u/apps/app/shared/sockets/unicorn.sock,crnl
--&amp;gt;GET /session/new HTTP/1.1
--&amp;gt;Host: thehostname.com
--&amp;gt;X-Forwarded-Proto: https
--&amp;gt;
HTTP/1.1 200 OK
Date: Fri, 02 Dec 2011 14:37:23 GMT
Status: 200 OK
Connection: close
Strict-Transport-Security: max-age=31536000
Content-Type: text/html; charset=utf-8
X-UA-Compatible: IE=Edge,chrome=1
ETag: &amp;#34;2346c47c7cb3bc37729e42fc8b20c821&amp;#34;
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: _x_session=blablabla; path=/; HttpOnly; secure
X-Request-Id: c0a374f460d1b1205df450ab77dd2328
X-Runtime: 0.159219

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;#34;en&amp;#34; data-behavior=&amp;#34;wallpaper&amp;#34;&amp;gt;
&amp;lt;head&amp;gt;
etc.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For those interested in the relevance of the crnl option at the end of the socket path, this from the man page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Converts the default line termination character NL (&amp;rsquo;n&amp;rsquo;, 0x0a)&lt;/li&gt;
&lt;li&gt;to/from CRNL (&amp;ldquo;rn&amp;rdquo;, 0x0d0a) when writing/reading on this&lt;/li&gt;
&lt;li&gt;channel (example). Note: socat simply strips all CR characters.&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
</description>
    </item>
    
      
      <item>
      <title>Cloud email service price comparison</title>
      <link>https://willj.net/posts/cloud-email-service-price-comparison/</link>
      <pubDate>Wed, 30 Nov 2011 21:27:42 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/cloud-email-service-price-comparison/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Larger interactive versions of all the graphs on this page are available &lt;a href=&#34;cloud_email_provider_price_comparison.html&#34;&gt;here&lt;/a&gt;.&lt;/strong&gt; &lt;strong&gt;Update:&lt;/strong&gt; Added &lt;a href=&#34;https://www.mailgun.com/&#34; title=&#34;Mailgun&#34;&gt;Mailgun&lt;/a&gt; to the &lt;a href=&#34;http://willj.net/static/cloud_email_provider_price_comparison.html&#34;&gt;graphs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Earlier this year I posted a &lt;a href=&#34;https://willj.net/posts/should-i-switch-from-sendgrid-to-amazon-ses&#34; title=&#34;Sendgrid and Amazone SES price comparison&#34;&gt;price comparison&lt;/a&gt; between &lt;a href=&#34;https://sendgrid.com/&#34; title=&#34;Sendgrid&#34;&gt;Sendgrid&lt;/a&gt;, and the then newly available &lt;a href=&#34;http://aws.amazon.com/ses/&#34; title=&#34;Amazon SES&#34;&gt;Amazon SES&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Tim Falls commented on the post saying that Sendgrid had updated their pricing:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since this post was published, we have released a new pricing structure *and* a new service tier that offers more email for less + a feature set and pricing model that you will find very competitive with SES.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;That was back in June, so it&amp;rsquo;s about time I produced an updated comparison. First, lets look at the difference between the old and new Sendgrid prices:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/cloud-email-service-price-comparison/images/screen-shot-2011-11-30-at-22-20-15.png&#34;
    alt=&#34;graph showing cost of email service providers&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Comparison of old and new Sendgrid prices&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Overall the up-front plan prices, and prices for email over allowance have remained the same, but email allowance within each plan has increased. The exception is the Silver plan where email over allowance has increased by $0.0001/email. New to the lineup is the Lite plan.&lt;/p&gt;
&lt;p&gt;More interesting is how these new prices compare to the competitors. I&amp;rsquo;ve added in Amazon SES, and Postmark too:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/cloud-email-service-price-comparison/images/screen-shot-2011-12-01-at-00-42-52.png&#34;
    alt=&#34;graph showing cost of email service providers&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Sendgrid, Postmark and Amazon SES price comparison&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The most notable differences here are the inclusion of &lt;a href=&#34;http://postmarkapp.com/&#34; title=&#34;Postmark&#34;&gt;Postmark&lt;/a&gt;, and the the Sendgrid Lite plan that shadows Amazon SES. I&amp;rsquo;d guess this was added purely to compete with Amazon. As in my last post it is hard to see what is going on with smaller numbers of emails being sent, here&amp;rsquo;s a zoom on the origin:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/cloud-email-service-price-comparison/images/screen-shot-2011-12-01-at-00-42-57.png&#34;
    alt=&#34;graph showing cost of email service providers&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Price comparison for small numbers of emails sent&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Here you can see the Sendgrid Lite plan shadowing Amazon and the Postmark costs heading up rapidly.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;It seems Sendgrid have just added an &amp;lsquo;Amazon SES&amp;rsquo; plan to pull back any customers that would have chosen SES based on price. It&amp;rsquo;s probably a good move, and it will allow easy transition into their more &amp;lsquo;premium&amp;rsquo; plans if you sign up and later decide to change plan.&lt;/p&gt;
&lt;p&gt;Given the advertised features of Postmark compared to the price it seems hard to consider using them. They seem to have some fairly well known customers though, so if anyone has used Postmark leave a comment with how that is working out for you.&lt;/p&gt;
&lt;p&gt;So which email cloud provider should you use? Use the graphs I made, but price is only going to be one factor, so check what each provider offers. I&amp;rsquo;ve linked to all the pricing pages below.&lt;/p&gt;
&lt;h3 id=&#34;price-sources&#34;&gt;Price sources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://sendgrid.com/pricing&#34;&gt;Sendgrid prices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://postmarkapp.com/pricing&#34;&gt;Postmark prices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://aws.amazon.com/ses/pricing&#34;&gt;Amazon SES prices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.mailgun.com/pricing&#34;&gt;Mailgun prices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
      
      <item>
      <title>Should I switch from Sendgrid to Amazon SES?</title>
      <link>https://willj.net/posts/should-i-switch-from-sendgrid-to-amazon-ses/</link>
      <pubDate>Tue, 25 Jan 2011 21:53:07 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/should-i-switch-from-sendgrid-to-amazon-ses/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Update: A new comparison with updated Sendgrid prices, and Postmark is available &lt;a href=&#34;https://willj.net/posts/cloud-email-service-price-comparison&#34;&gt;here&lt;/a&gt; &amp;ldquo;Sendgrid, Postmark and Amazon SES price comparison&amp;rdquo;).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Probably yes, at least if price is your main concern and you are just concerned with sending email and not with extras. I wanted to see just how the &lt;a href=&#34;http://aws.amazon.com/ses/&#34;&gt;Amazon SES&lt;/a&gt; prices stacked up against (that I am aware of) the next cheapest provider, &lt;a href=&#34;http://sendgrid.com/&#34;&gt;Sendgrid&lt;/a&gt; so I graphed it:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/should-i-switch-from-sendgrid-to-amazon-ses/images/emails-price-comparison1.png&#34;
    alt=&#34;A graph showing the difference between prices for Sendgrid and AWS SES&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Cost comparison for Amazon SES/Sendgrid&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;SendGrid can&amp;rsquo;t be too happy with that, in short at no point is it better to go with SendGrid over SES if you are only taking price into account. Of course SendGrid have &lt;a href=&#34;https://sendgrid.com/pricing/&#34;&gt;value-add over just plain email&lt;/a&gt; sending, you decide if it&amp;rsquo;s worth the premium, but for me the only feature I&amp;rsquo;d want would be the &amp;lsquo;Whitelabel&amp;rsquo; option, and Amazon SES has that included.&lt;/p&gt;
&lt;p&gt;Note that you get 2000 emails per day free with Amazon SES if you send from an &lt;a href=&#34;http://aws.amazon.com/ec2/&#34;&gt;Amazon EC2&lt;/a&gt; instance, but at this scale there is very little visible difference in cost. I thought it would be useful to take into account the cost of an EC2 instance, even if you have your main server elsewhere you could run your email processing on a micro or small EC2 machine to take advantage of the 2000 free emails per day, here&amp;rsquo;s a zoom in on the origin:&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/should-i-switch-from-sendgrid-to-amazon-ses/images/email-prices-plus-server.png&#34;
    alt=&#34;A graph showing the difference between prices for Sendgrid and AWS SES, including spinning up a server to send mail from&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Cost comparison for Amazon SES/Sendgrid &amp;#43; EC2 instance cost&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;So, there is no point in spinning up an EC2 instance to take advantage of the 2000 free emails per day.&lt;/p&gt;
&lt;p&gt;I will be interested in SendGrid&amp;rsquo;s response to this. Possibly lowering prices? For me certainly their value-add isn&amp;rsquo;t worth the extra cost over Amazon SES.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Rewriting URL params in nginx</title>
      <link>https://willj.net/posts/rewriting-url-params-in-nginx/</link>
      <pubDate>Sat, 07 Mar 2009 14:30:37 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/rewriting-url-params-in-nginx/</guid>
      <description>&lt;p&gt;I came across this problem recently, a customer was moving to Ruby on Rails from another framework/language (.NET I think) and needed to re-write a bunch of URLs. Some needed the query parameters rewriting too. One example was rewriting the old search path, so the old URL:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://somedomain.com/OldSearchPath.aspx?qry=things&amp;amp;page=4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;would become:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://somedomain.com/search?query=things&amp;amp;page=4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This should be fairly simple except for the &lt;em&gt;qry&lt;/em&gt; parameter needed to be changed to &lt;em&gt;query&lt;/em&gt;. A bit of googling didn&amp;rsquo;t turn up much but with some experimentation I came up with this using the pre-populated nginx $args variable:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;location /OldSearchPath.aspx {
  if ($args ~* qry=(.+)) {
    set $args query=$1;
  }
}
rewrite ^.+$ /search redirect;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It even leaves the other parameters intact, so the pagination will still work.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Tricks of the Trade</title>
      <link>https://willj.net/posts/tricks-of-the-trade/</link>
      <pubDate>Thu, 12 Apr 2007 19:04:33 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/tricks-of-the-trade/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://www.themorningnews.org/archives/how_to/tricks_of_the_trade.php&#34; title=&#34;Tricks of the trade&#34;&gt;Interesting article&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;hellip;I recently asked readers for their &amp;ldquo;tricks of the trade,&amp;rdquo; and was amazed by the response. It seems every profession is rich with clever little occupational secrets.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Here is one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Juggler&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With any routine under seven minutes (which is almost all of them), you only really need one thing: a good closer. And there are only two things you really need to know about a great closer. First, it needs to be impressive. That sounds obvious, but most beginning jugglers think &amp;ldquo;difficult&amp;rdquo; and &amp;ldquo;impressive&amp;rdquo; are synonymous. Your closer must &lt;em&gt;look&lt;/em&gt; hard, but there’s no real reason it has to &lt;em&gt;be&lt;/em&gt; hard. Secondly, you should intentionally blow your closer on the first two tries. If you get it on the first try it looks too easy, but if you &amp;ldquo;miss&amp;rdquo; it a few times it looks harder and builds tension.&lt;/p&gt;&lt;/blockquote&gt;
</description>
    </item>
    
      
      <item>
      <title>A great &#39;site unavailable&#39; message</title>
      <link>https://willj.net/posts/a-great-site-unavailable-message/</link>
      <pubDate>Fri, 14 Jul 2006 16:49:02 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/a-great-site-unavailable-message/</guid>
      <description>&lt;p&gt;Seen on &lt;a href=&#34;https://www.fish4.co.uk/&#34; title=&#34;fish4&#34;&gt;Fish4&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thank you for coming to Fish4 this morning.&lt;/p&gt;
&lt;p&gt;Unfortunately the fish4 website is unavailable due to the failure of a very expensive piece of Sun hardware (Sun 6900). A Sun engineer is at the data centre but didn&amp;rsquo;t think to bring the replacement part with him.&lt;/p&gt;
&lt;p&gt;We hope the sun engineer will have repaired the hardware by 12pm, and will update this estimate if necessary as the work progresses.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Here is a screengrab of the error:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://willjessop4.files.wordpress.com/2006/07/fish4_error_large.png&#34;&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2006/07/fish4_error_large.png&#34; alt=&#34;&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>99 bottles of Ruby beer on the wall</title>
      <link>https://willj.net/posts/99-bottles-of-ruby-beer-on-the-wall/</link>
      <pubDate>Wed, 05 Jul 2006 18:32:24 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/99-bottles-of-ruby-beer-on-the-wall/</guid>
      <description>&lt;p&gt;A while back a friend and I had a 99 bottles of beer on the wall one-liner competition in &lt;a href=&#34;http://ruby-lang.org/&#34; title=&#34;Ruby&#34;&gt;Ruby&lt;/a&gt;. I just found this in my home directory and so am claiming it as my entry:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;def b(c)&amp;quot;#{c} bottle#{c&amp;gt;1?&amp;quot;s&amp;quot;:&amp;quot;&amp;quot;} of beer on the wall&amp;quot;end;99.downto(1){|x|$&amp;gt;0?x-1:99)}.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It weighs in at a hefty 206 characters and I know it is possible to get it smaller than this, but it is way too much of a time-sink for me to try.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>Fixing the &#39;Memory card error&#39; on the Canon IXUS 400 / S3</title>
      <link>https://willj.net/posts/fixing-the-memory-card-error-on-the-canon-ixus-400/</link>
      <pubDate>Sun, 12 Feb 2006 16:29:42 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/fixing-the-memory-card-error-on-the-canon-ixus-400/</guid>
      <description>&lt;p&gt;The day after my daughter Holly was born my Canon IXUS 400 camera started giving a &amp;lsquo;Memory card error&amp;rsquo; and refused to save anything to the compact flash card. I assumed that this meant that there was an error with the memory card so I bought a brand new one and was slightly cheesed off when the IXUS gave the same &amp;lsquo;Memory card error&amp;rsquo; message after installing it.&lt;/p&gt;
&lt;p&gt;A bit of googling revealed that a number of people have had this error with the Canon IXUS s3 and that the problem was solved by opening the case and removing the internal battery. The specs of the IXUS 400 are similar to that of the S3 and the chassis are practically identical, so I guessed they may well share a fair few components, and therefore problems. I was not that keen on the idea of doing this however until I discovered that Canon wanted to charge me nearly £100 to fix it (including the cost of postage).&lt;/p&gt;
&lt;p&gt;It seems a bit cheeky asking for that amount of money to fix a problem that is effectively a design flaw, so I went for the DIY option and it seems to have worked, I have only taken about 20 photos, but as the camera would not allow any to be taken before, this is a significant improvement!&lt;/p&gt;
&lt;p&gt;For anyone wanting to do the same here are some photos of what to look for. This one is the back of the camera with the case taken off.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fixing-the-memory-card-error-on-the-canon-ixus-400/images/naked_ixus.jpg&#34;
    alt=&#34;A Canon IXUS 400 without it&amp;#39;s case on showing circuitry&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;A naked Canon IXUS 400&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;And this one is of the front of the camera. The battery is under the circled bit of metal film which was stuck down and had to be peeled off to get to the battery which is mounted in a clip just underneath.&lt;/p&gt;
&lt;figure class=&#34;full&#34;&gt;&lt;img src=&#34;https://willj.net/posts/fixing-the-memory-card-error-on-the-canon-ixus-400/images/naked_ixus_highlighted_battery.jpg&#34;
    alt=&#34;A camera without it&amp;#39;s case on with a red circle added to show battery location&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;The battery is under the metal film which can be peeled back carefully&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The battery popped out really easily with a small flat screwdriver. I put the battery back in, put the camera back together and the camera worked (I had to format the memory card first).&lt;/p&gt;
&lt;p&gt;Some tips if you are going to try this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have a very small flat and cross head screwdriver.&lt;/li&gt;
&lt;li&gt;Make a note of where the screws came from, many are different lengths.&lt;/li&gt;
&lt;li&gt;Remember which order the body panels and parts came off.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don&amp;rsquo;t attempt this if you are not confident in doing so, if you break your camera it is entirely your fault, and this will probably invalidate your warranty (mine had expired already). This whole experience has shaken my confidence in Canon cameras, I will be looking at alternative makes for my next purchase.&lt;/p&gt;
</description>
    </item>
    
      
      <item>
      <title>New hard disc</title>
      <link>https://willj.net/posts/new-hard-disc/</link>
      <pubDate>Wed, 09 Nov 2005 21:24:40 +0000</pubDate>
      <author>will@willj.net (Will Jessop)</author>
      <guid>https://willj.net/posts/new-hard-disc/</guid>
      <description>&lt;p&gt;I bought a new hard disc. It probably doesn&amp;rsquo;t work anymore, but then it did only cost me £5.20. I don&amp;rsquo;t care what anyone says, I like it. It is hanging behind my desk at work.&lt;/p&gt;
&lt;p&gt;Here is the eBay description:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;14&amp;quot; hard disk platter from the 1970s&lt;/p&gt;
&lt;p&gt;From the days when programmers didn&amp;rsquo;t eat quiche!&lt;/p&gt;
&lt;p&gt;This platter from a hard disk drive came from a Hull University mainframe in 1978. The disk is 14 inches (35.5cm) in diameter and 1.5mm thick.&lt;/p&gt;
&lt;p&gt;It is made from a hard aluminium alloy coated with magnetic material. One side is covered with a random collection of supermarket price and product labels of the period. Even though it has been used as a rather lethal frisbee, it is still perfectly flat.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;And here are some photos:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;http://willjessop4.files.wordpress.com/2005/11/hd_sticker_side.jpg&#34; alt=&#34;&#34;&gt;
&lt;img src=&#34;http://willjessop4.files.wordpress.com/2005/11/hd_detail_2.jpg&#34; alt=&#34;&#34;&gt;
&lt;img src=&#34;http://willjessop4.files.wordpress.com/2005/11/hd_detail_3.jpg&#34; alt=&#34;&#34;&gt;
&lt;img src=&#34;http://willjessop4.files.wordpress.com/2005/11/hd_plain_side.jpg&#34; alt=&#34;&#34;&gt;
&lt;img src=&#34;http://willjessop4.files.wordpress.com/2005/11/hd_detail_1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
</description>
    </item>
    </channel>
</rss>
