<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[blog.MikeBourgeous]]></title>
  <link href="https://blog.mikebourgeous.com/atom.xml" rel="self"/>
  <link href="https://blog.mikebourgeous.com/"/>
  <updated>2026-02-21T12:23:30-07:00</updated>
  <id>https://blog.mikebourgeous.com/</id>
  <author>
    <name><![CDATA[Mike Bourgeous]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[From missing parentheses to memory corruption: how one typo crashed Ruby and uncovered two core bugs]]></title>
    <link href="https://blog.mikebourgeous.com/2026/02/21/from-midi-to-memory-corruption-how-one-typo-uncovered-two-bugs-in-ruby/"/>
    <updated>2026-02-21T12:30:00-07:00</updated>
    <id>https://blog.mikebourgeous.com/2026/02/21/from-midi-to-memory-corruption-how-one-typo-uncovered-two-bugs-in-ruby</id>
    <content type="html"><![CDATA[
      <p><a href="https://bugs.ruby-lang.org/issues/21220"><figure class="image thumbnail half-right"><img src="https://blog.mikebourgeous.com/images/2026/02/21/from-midi-to-memory-corruption-how-one-typo-uncovered-two-bugs-in-ruby/ruby_bug_21220.png" title="Ruby bug #21220" alt="Ruby bug $21220"><figcaption class="caption-wide">Ruby bug #21220</figcaption></figure></a></p>

<div class="panel-group" id="tldrsummary-container">
<div class="panel panel-default">
<div class="panel-heading" id="tldrsummary-heading">
<a style="display: block" role="button" data-toggle="collapse" data-parent="#tldrsummary-container" href="#tldrsummary-content">TLDR: Click here if you just want the highlights</a>
</div>
<div id="tldrsummary-content" class="panel-collapse collapse" aria-labelledby="tldrsummary-heading">
<div class="panel-body">
<ul>
<li>Ruby&#39;s range syntax has lower precedence than method invocation, so
<code>1..16.size</code> returns the <code>Range</code> <code>1..8</code> (probably <code>1..4</code> on 32-bit systems),
while <code>(1..16).size</code> returns the <code>Integer</code> <code>16</code>.  Because of this, we need to
wrap a range in parentheses or store it in a variable when we want to call a
method on the range.</li>
<li>I missed the parentheses around a range during a late night coding session.</li>
<li>Ruby parsed this as a <a href="https://docs.ruby-lang.org/en/3.4/syntax/control_expressions_rdoc.html#label-Flip-Flop">flip-flop
operator</a>
but my program appeared to work normally.</li>
<li>My test suite uses SimpleCov to gather code coverage metrics.</li>
<li>Ruby 3.4 switched to the PRISM parser.</li>
<li>The PRISM compiler was generating a line number of zero for flip-flop
operators.</li>
<li>The Ruby code coverage system stores line counts in an <code>Array</code>.</li>
<li>A line number of zero would reference memory before the start of the <code>Array</code>.</li>
<li>Memory allocators use tags before and/or after allocated blocks to record
information about the allocation.</li>
<li>Writing the line count for line zero corrupted the heap by overwriting the
allocator&#39;s tags.</li>
<li>The program would crash some time later when the garbage collector
deallocated memory and libc found the heap corruption.</li>
<li><a href="https://github.com/mike-bourgeous/mb-sound/issues/36">mb-sound issue 36</a></li>
<li><a href="https://bugs.ruby-lang.org/issues/21220">Ruby issue 21220</a></li>
<li><a href="https://bugs.ruby-lang.org/issues/21259">Ruby issue 21259</a></li>
</ul>

</div>
</div>
</div>
</div>


<p>Back in March of 2025 I started what should have been a straightforward Ruby
version upgrade.  Little did I know I was about to fall down a <em>multi-day
rabbit hole</em> that would ultimately reveal <a href="https://bugs.ruby-lang.org/issues/21220">a memory corruption bug</a> (now
fixed) deep within core Ruby systems.</p>

<p>Often when you make a typo or miss an operator in code the program simply
doesn&rsquo;t work.  But there are those rare cases where you get a subtle,
insidious change that appears to work correctly.  This is the latter case, with
missing parentheses leading to a crash due to memory corruption.</p>

<p>Here&rsquo;s a bit of foreshadowing (did you know that Ruby has an operator called
<a href="https://docs.ruby-lang.org/en/3.4/syntax/control_expressions_rdoc.html#label-Flip-Flop">the flip-flop operator</a>?):</p>

<figure class="code">

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span></span><span class="k">raise</span><span class="w"> </span><span class="s1">&#39;Invalid channel&#39;</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="mi">1</span><span class="o">..</span><span class="mi">16</span><span class="o">.</span><span class="n">cover?</span><span class="p">(</span><span class="n">channel</span><span class="p">)</span>
</span><span class='line'><span class="c1"># vs.</span>
</span><span class='line'><span class="k">raise</span><span class="w"> </span><span class="s1">&#39;Invalid channel&#39;</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">16</span><span class="p">)</span><span class="o">.</span><span class="n">cover?</span><span class="p">(</span><span class="n">channel</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>




<p class="wide-caption">How will these two lines behave?</p>


<p></figure></p>

<p>Keep reading to see how code coverage, automated testing, uncommon operators,
and out-of-bounds array writes all converge in a very unexpected way.</p>


      <p><a href="https://blog.mikebourgeous.com/2026/02/21/from-midi-to-memory-corruption-how-one-typo-uncovered-two-bugs-in-ruby/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Can Ruby do audio?  Yes, yes it can.  This video proves it.]]></title>
    <link href="https://blog.mikebourgeous.com/2026/02/15/can-ruby-do-audio-yes/"/>
    <updated>2026-02-15T15:00:00-07:00</updated>
    <id>https://blog.mikebourgeous.com/2026/02/15/can-ruby-do-audio-yes</id>
    <content type="html"><![CDATA[
      <p><aside>This video is about reverb.  This post is about Ruby.  Yet they are also
part of a lifelong quest to find and redefine the edges of what people consider
possible.  A change of perspective can reveal the inherent simplicity within
the apparently complex.  This quest is incomplete and I don&rsquo;t yet have the
neat, packaged answer that ties everything together, but keep this idea in mind
while you read and watch.</aside></p>

<p>Something you should know about me is that I like to learn about my tools by
making them do things they aren&rsquo;t supposed to do.  In line with that, almost
six years ago I asked a question (worded slightly differently): <a href="https://blog.mikebourgeous.com/2021/03/10/why-cant-we-use-ruby-for-sound/">Can we use
Ruby for sound?</a>  As far as I&rsquo;m concerned, my most recent project continues
to answer that question with a resounding, reverberating YES.</p>

<p>In December I live-coded a fully functional reverb effect using <a href="https://www.ruby-lang.org">Ruby</a> and
the <a href="https://github.com/mike-bourgeous/mb-sound">mb-sound library</a> I developed for my <a href="https://www.youtube.com/playlist?list=PLpRqC8LaADXnwve3e8gI239eDNRO3Nhya">YouTube video series</a>, and
since then I&rsquo;ve been working nonstop on improving the reverb and making a video
about it.</p>

<hr />

<iframe width="560" height="315"
src="https://www.youtube-nocookie.com/embed/Yi2CfjE2pOo" frameborder="0"
allowfullscreen></iframe>


<hr />

<p>This latest video, inspired by a <a href="https://www.youtube.com/watch?v=6ZK2Goiyotk">presentation at ADC21</a>, uses data
visualization and animation to explore the concept of reverberation, my
implementation of the reverb design from that presentation, and the debugging
process required to get the reverb working live.  You can <a href="https://www.youtube.com/watch?v=Yi2CfjE2pOo">check out the video
on YouTube</a>, or continue reading here for some extra backstory and a
complete video transcript.</p>


      <p><a href="https://blog.mikebourgeous.com/2026/02/15/can-ruby-do-audio-yes/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Debugging live apps &ndash; SIGQUIT for the win]]></title>
    <link href="https://blog.mikebourgeous.com/2024/11/26/debugging-live-apps-sigquit-for-the-win/"/>
    <updated>2024-11-26T16:41:52-07:00</updated>
    <id>https://blog.mikebourgeous.com/2024/11/26/debugging-live-apps-sigquit-for-the-win</id>
    <content type="html"><![CDATA[
      <p><figure class="image img-thumbnail half-right"><a href="https://blog.mikebourgeous.com/images/2024/11/26/debugging-live-apps-sigquit-for-the-win/sigquit_backtrace_example.png" title=""><img src="https://blog.mikebourgeous.com/images/2024/11/26/debugging-live-apps-sigquit-for-the-win/sigquit_backtrace_example.png" title="Example SIGQUIT stack trace from mb-util rubygem" ><figcaption class="caption-wide">Example SIGQUIT stack trace from mb-util rubygem</figcaption></a></figure></p>

<p>Hey there, everyone!  This is just a quick post to share a debugging technique
I&rsquo;ve found useful and that I <a href="https://github.com/mike-bourgeous/mb-util?tab=readme-ov-file#debugging-a-running-process">recently added to mb-util</a>.  Today I&rsquo;m talking
about using <code>SIGQUIT</code> to trigger some kind of debugging action in an
application, such as opening a REPL or logging a stack trace.</p>

<p>The reason <code>SIGQUIT</code> is useful is that most terminals will send that signal if
you press Ctrl-\ (control and backslash), and many server environments also
have a mechanism for sending UNIX signals.</p>

<p>I&rsquo;m not the first person to do this of course.  My inspiration comes from the
JVM, where SIGQUIT will print stack traces and JVM statistics, but I believe
the idea goes back further.  Here I&rsquo;ll show how to apply this concept to a Ruby
application, but you can do the same thing in any language.</p>


      <p><a href="https://blog.mikebourgeous.com/2024/11/26/debugging-live-apps-sigquit-for-the-win/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Observability and instrumentation from a systems perspective]]></title>
    <link href="https://blog.mikebourgeous.com/2024/09/08/observability-and-monitoring-from-a-systems-perspective/"/>
    <updated>2024-09-08T11:33:11-06:00</updated>
    <id>https://blog.mikebourgeous.com/2024/09/08/observability-and-monitoring-from-a-systems-perspective</id>
    <content type="html"><![CDATA[
      <p><figure class="image img-thumbnail half-right"><img src="https://blog.mikebourgeous.com/images/2024/09/08/observability-and-monitoring-from-a-systems-perspective/car_system_diagram_with_dashboard.jpg"  alt="A car dashboard and system diagram"></figure></p>

<p>Over the years of my engineering career I&rsquo;ve been involved in a number of
monitoring, observability, and visualization projects.  I&rsquo;ve found that many of
my system-oriented techniques learned from across industries aren&rsquo;t always
intuitively obvious to newer engineers, so I&rsquo;ve wanted to write about
the subject for some time.  Here you&rsquo;ll find my thoughts on observability,
instrumentation, monitoring, etc.</p>

<p><strong>The key insight for me has always been looking at any given system as a
<em>system</em> in the abstract sense.</strong>  A system of any kind has an intended (or
emergent) purpose, various inputs and outputs, and a number of interconnected
components.  Each component can in turn be viewed as a system and further
subdivided.  It is this layered breakdown of a system into components, and the
connections between them, that guides my approach to system observability.</p>

<p>Continue reading to find my take on what I mean by &ldquo;observability,&rdquo; what the
goal of observation is, and how I approach instrumenting a system.  I&rsquo;ll
provide examples from different types of system, and compare them to software
systems.</p>


      <p><a href="https://blog.mikebourgeous.com/2024/09/08/observability-and-monitoring-from-a-systems-perspective/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Learn more about the Fast Fourier Transform, animated in 3D]]></title>
    <link href="https://blog.mikebourgeous.com/2021/10/04/fast-fourier-transform-illustrated-in-3d/"/>
    <updated>2021-10-04T13:01:49-06:00</updated>
    <id>https://blog.mikebourgeous.com/2021/10/04/fast-fourier-transform-illustrated-in-3d</id>
    <content type="html"><![CDATA[
      <p>Once again it&rsquo;s time for <a href="https://www.youtube.com/watch?v=iyjIVSnrPSo">another episode</a> of my video series, <a href="https://www.youtube.com/playlist?list=PLpRqC8LaADXnwve3e8gI239eDNRO3Nhya">Code, Sound
&amp; Surround</a>!  This series is all about using 2D and 3D visualizations, code,
and sound to explore the relationships between math, sound, visuals, and
problem solving from a unique angle.  My goal is not necessarily to be a
one-stop source to learn these concepts, but rather to both provide an overview
of things you might not have heard of, and to present familiar concepts in an
unfamiliar way, to help unlock new insights and reveal the connections between
ideas.</p>

<p>This time we&rsquo;re reviewing how sound is digitized, quickly recapping filters,
and looking at the <a href="https://en.wikipedia.org/wiki/Fast_Fourier_transform">Fast Fourier Transform (FFT)</a> with some
never-before-seen 3D visualizations.  The video also briefly introduces
<a href="https://en.wikipedia.org/wiki/Analytic_signal">analytic signals</a> and sets the stage for future videos that will dive
further into analytic signals, synthesizers, and surround sound.  And don&rsquo;t
miss the synthesizer demo song at the end, showing just how much can be
accomplished with a few stages of simple signal processing.</p>

<hr />

<iframe width="560" height="315"
src="https://www.youtube-nocookie.com/embed/iyjIVSnrPSo" frameborder="0"
allowfullscreen></iframe>


<hr />

<p>As part of working on this video, I&rsquo;ve made hundreds of commits and added
thousands of lines of code to <a href="https://github.com/mike-bourgeous/mb-math">mb-math</a>, <a href="https://github.com/mike-bourgeous/mb-util">mb-util</a>, and <a href="https://github.com/mike-bourgeous/mb-sound">mb-sound</a>, so
check those out as well.  Also, all music from all of my videos is original,
either composed for this video series, or repurposed from my previous work.</p>

<p>Keep reading below for the video&rsquo;s backstory, a list of the concepts covered
in the video, and a transcript of the video.</p>


      <p><a href="https://blog.mikebourgeous.com/2021/10/04/fast-fourier-transform-illustrated-in-3d/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Voronoi diagrams and natural neighbor interpolation explained in video (with transcript)]]></title>
    <link href="https://blog.mikebourgeous.com/2021/06/09/voronoi-diagrams-and-natural-neighbor-interpolation-explained-in-video/"/>
    <updated>2021-06-09T13:55:40-06:00</updated>
    <id>https://blog.mikebourgeous.com/2021/06/09/voronoi-diagrams-and-natural-neighbor-interpolation-explained-in-video</id>
    <content type="html"><![CDATA[
      <p>My <a href="https://www.youtube.com/watch?v=jxOAU7YfypA">latest video</a> is live on YouTube!  In this beautifully animated tour of
<a href="https://en.wikipedia.org/wiki/Voronoi_diagram">Voronoi diagrams</a>, <a href="https://en.wikipedia.org/wiki/Delaunay_triangulation">Delaunay triangulation</a>, and <a href="https://en.wikipedia.org/wiki/Natural_neighbor_interpolation">natural neighbor
interpolation</a>, I explain the algorithms used in my <a href="https://github.com/mike-bourgeous/mb-geometry">mb-geometry rubygem</a>
for generating Delaunay triangulations and Voronoi partitions.  Then
interpolation is given as a practical application of these algorithms.</p>

<p>This video is part of my ongoing video series, <a href="https://www.youtube.com/playlist?list=PLpRqC8LaADXnwve3e8gI239eDNRO3Nhya">Code, Sound &amp; Surround</a>.</p>

<hr />

<iframe width="560" height="315"
src="https://www.youtube-nocookie.com/embed/jxOAU7YfypA" frameborder="0"
allowfullscreen></iframe>


<hr />

<p>You can keep reading for a partial transcript of the video, and I&rsquo;ve written
more about <a href="https://blog.mikebourgeous.com/2021/04/18/animated-graphics-with-ruby-and-voronoi-partitions/">Voronoi partitions, Delaunay triangulations, and mb-geometry</a>
previously.</p>


      <p><a href="https://blog.mikebourgeous.com/2021/06/09/voronoi-diagrams-and-natural-neighbor-interpolation-explained-in-video/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Animated graphics with Ruby and Voronoi partitions]]></title>
    <link href="https://blog.mikebourgeous.com/2021/04/18/animated-graphics-with-ruby-and-voronoi-partitions/"/>
    <updated>2021-04-18T18:18:34-06:00</updated>
    <id>https://blog.mikebourgeous.com/2021/04/18/animated-graphics-with-ruby-and-voronoi-partitions</id>
    <content type="html"><![CDATA[
      <p><figure class="image half-right img-thumbnail"><video src="https://blog.mikebourgeous.com/images/2021/04/18/animated-graphics-with-ruby-and-voronoi-partitions/fish_comp.mp4"  alt="An animated Voronoi diagram" muted autoplay loop></video></figure></p>

<!-- RANDOM_SEED=4 XRES=960 YRES=720 bin/voronoi_transitions.rb /tmp/fish.mp4 test_data/lines.json 0 60 __shuffle 90 240 -->


<!-- ffmpeg -i /tmp/fish.mp4 -r:v 30 -c:v libx264 -preset veryslow -tune animation /tmp/fish_comp.mp4 -->


<p>I&rsquo;ve been writing a lot of code for my next video in <a href="https://www.youtube.com/playlist?list=PLpRqC8LaADXnwve3e8gI239eDNRO3Nhya">Code, Sound &amp;
Surround</a>.  One small part of that has turned out to be interesting enough to
show off on its own.  I built some <a href="https://github.com/mike-bourgeous/mb-geometry">tools for plotting and animating <strong>Voronoi
diagrams</strong> in Ruby</a>, and now I&rsquo;ve published them on GitHub.</p>

<p><em>Update:</em> I&rsquo;ve also made a <a href="https://blog.mikebourgeous.com/2021/06/09/voronoi-diagrams-and-natural-neighbor-interpolation-explained-in-video/">YouTube video showing these geometric algorithms</a>.</p>

<p>A <strong><a href="https://en.wikipedia.org/wiki/Voronoi_diagram">Voronoi diagram</a></strong> (Voronoi rhymes with &ldquo;enjoy&rdquo;) or <strong>Voronoi
partition</strong> shows which areas are closest to a set of starting points.
Choose one or more points on a 2D plane (you can also do 3D or
higher, but I haven&rsquo;t done that).  Draw a convex polygon around each point,
showing the area that is closest to that point.  That&rsquo;s a Voronoi diagram.</p>

<p>Each edge of a polygon should be half-way between two points, and each corner
of a polygon is equally distant to three or more points.  Every polygon has one
point inside it, and every point has one polygon around it, with no overlap.
Give each surrounding polygon its own color, and you get something like this:</p>


      <p><a href="https://blog.mikebourgeous.com/2021/04/18/animated-graphics-with-ruby-and-voronoi-partitions/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Why can't we use Ruby for sound?]]></title>
    <link href="https://blog.mikebourgeous.com/2021/03/10/why-cant-we-use-ruby-for-sound/"/>
    <updated>2021-03-10T18:21:38-07:00</updated>
    <id>https://blog.mikebourgeous.com/2021/03/10/why-cant-we-use-ruby-for-sound</id>
    <content type="html"><![CDATA[
      <p><a href="https://www.youtube.com/watch?v=hMfEea9XVSs"><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2021/03/10/why-cant-we-use-ruby-for-sound/video_0.jpg"  alt="Code Sound &amp; Surround Teaser"></figure></a></p>

<p>Ruby is one of those programming languages that seems to get slotted into a
specific use-case in people&rsquo;s minds.  You use Ruby for web development, C or C++
for high-performance code, Java for banks and insurance companies, Python for
machine learning, Rust for trendily secure code, Typescript for web frontends.
Everyone just &ldquo;knows&rdquo; these things.  But why?</p>

<p>For a long time I had wanted to make my own A/V receiver with my own audio
algorithms.  Most people just buy a TV and call it done.  Some people will buy a
TV and a sound bar and call it done.  A few more will buy a TV, a receiver, and
some speakers and call it done.  And the super dedicated (or super rich) will
buy an expensive hi-fi system and/or home theater.  But not me.  Instead of just
buying a receiver and pushing that &ldquo;Dolby&rdquo; or &ldquo;DTS&rdquo; button, why not do things
the hard way, and make my own?</p>

<p>Put those two things together &ndash; my love of Ruby, and my love of sound &ndash; and
mix in a bit of 2020 lockdown.  I just <em>had</em> to prove that Ruby is good for more
than web development.  I ended up writing my own stereo-to-surround-sound
decoder (more than one, in fact), and a bunch of other audio code, all in Ruby.
Not content with that, I&rsquo;ve <a href="https://github.com/mike-bourgeous/mb-sound">released a lot of my code on GitHub</a> and I&rsquo;m
making <a href="https://www.youtube.com/playlist?list=PLpRqC8LaADXnwve3e8gI239eDNRO3Nhya">videos to teach others about sound</a>, and about Ruby.</p>

<p>This series of <a href="https://www.youtube.com/playlist?list=PLpRqC8LaADXnwve3e8gI239eDNRO3Nhya">videos</a> and posts is all about my journey to find out just what
Ruby is capable of, and to make the best-sounding surround decoder ever written
in Ruby.</p>


      <p><a href="https://blog.mikebourgeous.com/2021/03/10/why-cant-we-use-ruby-for-sound/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Opening knc: the Depth Camera Controller UI]]></title>
    <link href="https://blog.mikebourgeous.com/2021/03/09/opening-knc/"/>
    <updated>2021-03-09T20:12:49-07:00</updated>
    <id>https://blog.mikebourgeous.com/2021/03/09/opening-knc</id>
    <content type="html"><![CDATA[
      <p><a href="https://github.com/nitrogenlogic/knc"><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2021/03/09/opening-knc/knc_ui.png"  alt="knc user interface"></figure></a></p>

<p>I&rsquo;ve been working hard on a <a href="https://www.youtube.com/playlist?list=PLpRqC8LaADXnwve3e8gI239eDNRO3Nhya">YouTube project</a> lately, which I&rsquo;ll blog about later.
For now, I&rsquo;m pleased to announce that I&rsquo;ve opened up the source code for
Nitrogen Logic&rsquo;s Depth Camera Controller browser-based UI, called <a href="https://github.com/nitrogenlogic/knc">knc</a>.</p>

<p><a href="https://github.com/nitrogenlogic/knc">knc</a> is a Ruby- and EventMachine-based service that serves a dynamic
browser-based UI (HTML, CSS, JS) for controlling Nitrogen Logic automation
systems and Philips Hue lights using the Kinect.</p>


      <p><a href="https://blog.mikebourgeous.com/2021/03/09/opening-knc/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Releasing knd: the backend Kinect interface]]></title>
    <link href="https://blog.mikebourgeous.com/2020/04/22/releasing-knd-the-backend-kinect-interface/"/>
    <updated>2020-04-22T11:50:31-07:00</updated>
    <id>https://blog.mikebourgeous.com/2020/04/22/releasing-knd-the-backend-kinect-interface</id>
    <content type="html"><![CDATA[
      <p><a href="https://github.com/nitrogenlogic/knd"><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2020/04/22/releasing-knd-the-backend-kinect-interface/knd-startup.png"  alt="knd startup"></figure></a></p>

<p>Hi, it&rsquo;s been a while.  So I actually uploaded this next component from Nitrogen
Logic, <a href="https://github.com/nitrogenlogic/knd">knd</a>, quite a while ago (October 2018).  But things got busy and I
never wrote the blog post.  So now that we&rsquo;re all on quarantine lockdowns and
have extra time, here&rsquo;s a very late announcement that knd is now open source!</p>

<p><a href="https://github.com/nitrogenlogic/knd">knd</a> provides the core Kinect backend interface for all Nitrogen Logic
controllers.  It&rsquo;s a background daemon written in C with a text interface over
TCP.  knd provides image, position, and zone data to the rest of the Nitrogen
Logic system, and performs the heavy lifting of all 3D distance and location
calculations.</p>

<p>A few highlights:</p>

<ul>
<li>Optimized approximated integer math functions using reciprocal multiplication
to get 30fps on SheevaPlugs, which lack floating point hardware.</li>
<li>Human- and machine-friendly TCP text-based command line interface.</li>
<li>Cross-compilation support through CMake.</li>
<li>Automatic stack trace printout of all threads when there is an error (not
always easy in C, but made possible by <a href="https://github.com/nitrogenlogic/nlutils">nlutils</a> and glibc).</li>
</ul>



      <p><a href="https://blog.mikebourgeous.com/2020/04/22/releasing-knd-the-backend-kinect-interface/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Open sourcing nlutils: Nitrogen Logic's C utility library]]></title>
    <link href="https://blog.mikebourgeous.com/2018/08/26/open-sourcing-nitrogen-logics-c-utility-library/"/>
    <updated>2018-08-26T20:29:52-07:00</updated>
    <id>https://blog.mikebourgeous.com/2018/08/26/open-sourcing-nitrogen-logics-c-utility-library</id>
    <content type="html"><![CDATA[
      <p><a href="https://github.com/nitrogenlogic/nlutils"><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2018/08/26/open-sourcing-nitrogen-logics-c-utility-library/nlutils_readme_screenshot.png"  alt="libnlutils on GitHub"></figure></a></p>

<p>If you&rsquo;ve read my previous post, you know that I&rsquo;m <a href="https://blog.mikebourgeous.com/2018/08/26/open-sourcing-my-old-startup-nitrogen-logic/">opening up some of the
source code</a> from my old startup, <a href="http://www.nitrogenlogic.com/">Nitrogen Logic</a>.  Here&rsquo;s the first
major piece of the Nitrogen Logic source code to go open source.  It&rsquo;s a core
utility library used by all of Nitrogen Logic&rsquo;s C projects, called <a href="https://github.com/nitrogenlogic/nlutils">nlutils</a>.</p>

<p>Because of C&rsquo;s very limited standard library compared to more modern and
full-featured languages, it&rsquo;s incredibly common for developers to write their
own core data structures and helper functions that they use over and over.
These include better string manipulation functions, linked lists, associative
arrays, etc. &ndash; things that we take for granted in languages like Ruby.</p>

<p><a href="https://github.com/nitrogenlogic/nlutils">nlutils</a> is the set of such tools for Nitrogen Logic&rsquo;s C projects.  Where
possible the code adheres to <a href="https://en.wikipedia.org/wiki/C99">C99</a> and <a href="https://en.wikipedia.org/wiki/POSIX">POSIX.1-2008</a>.  The header files
are thoroughly documented, so browse around the <code>include/</code> directory to see what
nlutils provides.  After meticulously reviewing the code and tests, I&rsquo;ve pushed
it to GitHub under the GNU AGPLv3 license for all to enjoy.</p>


      <p><a href="https://blog.mikebourgeous.com/2018/08/26/open-sourcing-nitrogen-logics-c-utility-library/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Nitrogen Logic is going open source!]]></title>
    <link href="https://blog.mikebourgeous.com/2018/08/26/open-sourcing-my-old-startup-nitrogen-logic/"/>
    <updated>2018-08-26T17:22:19-07:00</updated>
    <id>https://blog.mikebourgeous.com/2018/08/26/open-sourcing-my-old-startup-nitrogen-logic</id>
    <content type="html"><![CDATA[
      <p><a href="http://www.nitrogenlogic.com/"><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2018/08/26/open-sourcing-my-old-startup-nitrogen-logic/technology_that_responds_to_presence.png"  alt="Nitrogen Logic"></figure></a></p>

<p>It&rsquo;s been quite some time since my last post.  I&rsquo;ve been meaning to write more
about my old startup, <a href="http://www.nitrogenlogic.com/">Nitrogen Logic</a>, but as they say life gets busy.  But
now seems like a good time to start opening up more of the source code that
powered Nitrogen Logic.  It&rsquo;ll be slow going, but the first big C release,
<a href="https://blog.mikebourgeous.com/2018/08/26/open-sourcing-nitrogen-logics-c-utility-library">nlutils</a>, is already <a href="https://github.com/nitrogenlogic/nlutils">on GitHub</a>.</p>

<p>Since Nitrogen Logic was always a one-person show, there&rsquo;s nobody but me
stopping me from releasing, but also nobody pushing me onward.  I figured I
should finally take advantage of the rare opportunity to add 5+ years of my
career to my public portfolio and to the shared knowledge of our industry.</p>

<p>Any time you open source old code there&rsquo;s a lot of work involved.  In Nitrogen
Logic&rsquo;s case there are several major components to open up, each with its own
unique needs, and built on a plethora of different technologies:</p>


      <p><a href="https://blog.mikebourgeous.com/2018/08/26/open-sourcing-my-old-startup-nitrogen-logic/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[cliserver_rust: Learning Rust by reimplementing cliserver with Tokio]]></title>
    <link href="https://blog.mikebourgeous.com/2017/01/26/learning-rust-by-reimplementing-cliserver-with-tokio/"/>
    <updated>2017-01-26T21:59:16-07:00</updated>
    <id>https://blog.mikebourgeous.com/2017/01/26/learning-rust-by-reimplementing-cliserver-with-tokio</id>
    <content type="html"><![CDATA[
      <p><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2017/01/26/learning-rust-by-reimplementing-cliserver-with-tokio/cliserver_rust_checklist.png"  alt="Tasks to port cliserver"></figure></p>

<p>Lately I&rsquo;ve been reading about the <a href="https://www.rust-lang.org/">Rust programming language</a>, just for fun.
One of the ways I (and others) enjoy learning a new language or framework is
porting an old project into the new language, while trying to take advantage of
the language&rsquo;s features.</p>

<p>So to learn Rust, I&rsquo;ll be reimplementing my old <a href="https://blog.mikebourgeous.com/2011/01/13/cliserver-an-example-libevent-based-socket-se/">cliserver example for
libevent</a> using Rust&rsquo;s <a href="https://tokio.rs/">Tokio</a> crate.  At the risk of public
embarrassment, I will be <a href="https://github.com/mike-bourgeous/cliserver_rust/issues">tracking my progress using GitHub issues</a>.</p>


      <p><a href="https://blog.mikebourgeous.com/2017/01/26/learning-rust-by-reimplementing-cliserver-with-tokio/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ruby Gems for home automation: nlhue and xap_ruby]]></title>
    <link href="https://blog.mikebourgeous.com/2017/01/05/ruby-gems-for-home-automation-nlhue-and-xap-ruby/"/>
    <updated>2017-01-05T17:17:05-07:00</updated>
    <id>https://blog.mikebourgeous.com/2017/01/05/ruby-gems-for-home-automation-nlhue-and-xap-ruby</id>
    <content type="html"><![CDATA[
      <p><a href="https://github.com/nitrogenlogic"><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2017/01/05/ruby-gems-for-home-automation-nlhue-and-xap-ruby/nlhue_and_xap_ruby.png"  alt="Nitrogen Logic code on GitHub"></figure></a></p>

<p>The web interfaces for the <a href="http://www.nitrogenlogic.com/">Nitrogen Logic</a> <a href="http://www.nitrogenlogic.com/products/">depth and automation
controllers</a> are written in Ruby.  To talk to the Philips Hue lighting system
and some other DIY home automation systems, I created two Ruby libraries,
<a href="https://github.com/nitrogenlogic/nlhue">nlhue</a> and <a href="https://github.com/nitrogenlogic/xap_ruby">xap_ruby</a>.  I recently converted these libraries to Ruby Gems
available from RubyGems.org.</p>

<p>Both of them depend on EventMachine for fast network event handling, but that
also makes them a bit difficult to use.  They were developed in a bit of a
hurry, follow C rather than Ruby indentation, lack automated tests, and don&rsquo;t
represent the best code quality.  Nevertheless they have been battle tested in
real products working well for real people, and they may yet be useful.</p>

<p>Continue reading for more information about these gems.</p>


      <p><a href="https://blog.mikebourgeous.com/2017/01/05/ruby-gems-for-home-automation-nlhue-and-xap-ruby/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[MSSQL MERGE/UPSERT with Ruby and the Sequel gem]]></title>
    <link href="https://blog.mikebourgeous.com/2016/12/14/mssql-merge-upsert-with-ruby-and-the-sequel-gem/"/>
    <updated>2016-12-14T01:06:10-07:00</updated>
    <id>https://blog.mikebourgeous.com/2016/12/14/mssql-merge-upsert-with-ruby-and-the-sequel-gem</id>
    <content type="html"><![CDATA[
      <p>My last post contained some code snippets useful for <a href="https://blog.mikebourgeous.com/2016/12/13/interfacing-legacy-oracle-pl-slash-sql-and-modern-ruby-code/">working with an Oracle
database from Ruby</a>.  I&rsquo;ve also had to interface with Microsoft&rsquo;s SQL Server
database (to add data to a data warehouse) using Ruby and <a href="http://sequel.jeremyevans.net/">Sequel</a>.  Here&rsquo;s
a snippet for <a href="https://gist.github.com/mike-bourgeous/510ebf45939907d2e993e26590f4958a">using the <code>MERGE</code> statement with the Sequel gem</a>, useful
unless/until Sequel gets official <code>MERGE</code> support.  This snippet only supports
basic <code>UPSERT</code> functionality, where data is updated when the key is matched,
inserted when not matched.  It does support multi-column keys for matching.</p>

<div><script src='https://gist.github.com/510ebf45939907d2e993e26590f4958a.js'></script>
<noscript><pre><code># Code to perform a basic update/insert using MERGE.  Tested with MSSQL
# and the TinyTDS adapter.  Assumes DB contains a Sequel::Database.

require &#39;sequel&#39;

module Merge
  # Returns a Sequel::Dataset that will update or insert the given Array of
  # Hashes of +data+ into the given named +table+, with the given primary
  # +key+(s).  Hash key names in +data+ must match the table&#39;s column names
  # The dataset will return one row for each row that was inserted or updated,
  # with the action performed in the :$action column.
  #
  # Examples:
  #   Merge.merge(
  #     :schema1__table1,
  #     :col1,
  #     [{col1: 1, col2: 2, col3: 3}, ...]
  #   ).all
  #   # =&gt; [{ :$action =&gt; &#39;UPDATE&#39;, :line_id =&gt; 1 }, ...]
  #
  #   Merge.merge(
  #     :schema2__table2,
  #     [:col1, :col2],
  #     [{col1: 1, col2: 2, col3: 3}, ...]
  #   ).all
  #   # =&gt; [{ :$action =&gt; &#39;INSERT&#39;, :col1 =&gt; 1, :col2 =&gt; 2 }, ...]
  def self.merge(table, key, data)
    raise &#39;No data given&#39; if data.empty? || data.first.empty?

    # Ensure consistent column order
    cols = data.first.keys
    values = data.map{|h| cols.map{|k| h[k] } }

    key = [key] unless key.is_a?(Array)
    key_sql = ([&#39;? = ?&#39;] * key.size).join(&#39; AND &#39;)
    key_params = key.map{|k| [Sequel.qualify(:target, k), Sequel.qualify(:source, k)] }.flatten

    update_cols = (cols - key)
    update_sql = ([&#39;? = ?&#39;] * update_cols.size).join(&#39;, &#39;)
    update_params = update_cols.map{|k| [Sequel.qualify(:target, k), Sequel.qualify(:source, k)] }.flatten

    sql = &lt;&lt;-SQL
      MERGE INTO
        ? AS ?
      USING
        (VALUES
          #{([&#39;?&#39;] * values.size).join(&#39;, &#39;)}
        ) AS ? ?
      ON
        #{key_sql}
      WHEN MATCHED THEN
        UPDATE SET
          #{update_sql}
      WHEN NOT MATCHED THEN
        INSERT ? VALUES ?
      OUTPUT
        $action,
        #{([&#39;?&#39;] * key.size).join(&#39;, &#39;)}
      ;
    SQL

    DB[
      sql,
      table,
      :target,
      *values,
      :source,
      cols,
      *key_params,
      *update_params,
      cols,
      cols.map{|k| Sequel.qualify(:source, k) },
      *key.map{|k| Sequel.qualify(:source, k) },
    ]
  end
end</code></pre></noscript></div>


<p>The code builds the SQL dynamically since it has to insert a different number
of parameters based on how many columns are being updated or used as keys.</p>

<p>Make sure you read the code comments from the snippet.  Also make sure you&rsquo;ve
read up on how the Sequel gem qualifies schema, table, and column names using
double- and triple-underscore.</p>

<p>You&rsquo;ll need the following gems:</p>

<ul>
<li><a href="http://sequel.jeremyevans.net/">Sequel</a></li>
<li><a href="https://github.com/rails-sqlserver/tiny_tds">TinyTDS</a></li>
</ul>


      <p><a href="https://blog.mikebourgeous.com/2016/12/14/mssql-merge-upsert-with-ruby-and-the-sequel-gem/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Interfacing Legacy Oracle PL/SQL and Modern Ruby Code]]></title>
    <link href="https://blog.mikebourgeous.com/2016/12/13/interfacing-legacy-oracle-pl-slash-sql-and-modern-ruby-code/"/>
    <updated>2016-12-13T19:39:02-07:00</updated>
    <id>https://blog.mikebourgeous.com/2016/12/13/interfacing-legacy-oracle-pl-slash-sql-and-modern-ruby-code</id>
    <content type="html"><![CDATA[
      <p><a href="https://gist.github.com/mike-bourgeous/01d9a7b5db81dbe99c74caf0db2a0ad5"><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2016/12/13/interfacing-legacy-oracle-pl-slash-sql-and-modern-ruby-code/basic_ruby_plsql_gist.png"  alt="Ruby and PL/SQL GitHub Gist"></figure></a></p>

<p>My last couple of blog posts have been about the backend and middleware work I
did at my previous employer.  I wrote about two Ruby gems, <a href="https://blog.mikebourgeous.com/2016/11/16/data-validation-in-ruby-with-classyhash/">ClassyHash</a> and
<a href="https://blog.mikebourgeous.com/2016/11/22/hashformer-transform-data-in-ruby/">HashFormer</a>, that help with data validation and transformation in backend
APIs and in middleware.  Today we&rsquo;ll look briefly at some code snippets to help
Ruby developers interface with older systems that were written in Oracle PL/SQL,
possibly using Oracle applications like EBS (E-Business Suite).</p>

<p>To help launch my previous employer&rsquo;s updated site, I kind of dove head-first
into the deep end of PL/SQL, teaching myself the PL/SQL language, refactoring
thousands of lines of legacy code that was not designed with maintenance in
mind, and learning chunks of Oracle EBS (both the arcane UI and the even more
arcane internal PL/SQL interfaces) over a period of several months.  Let my pain
be your gain.  Continue reading for essential gems, some tips and tricks, and a
wrapper script to make the <code>sqlplus</code> command-line interface a little nicer for
Ruby developers.</p>


      <p><a href="https://blog.mikebourgeous.com/2016/12/13/interfacing-legacy-oracle-pl-slash-sql-and-modern-ruby-code/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Hashformer: Transform data in Ruby]]></title>
    <link href="https://blog.mikebourgeous.com/2016/11/22/hashformer-transform-data-in-ruby/"/>
    <updated>2016-11-22T21:03:14-07:00</updated>
    <id>https://blog.mikebourgeous.com/2016/11/22/hashformer-transform-data-in-ruby</id>
    <content type="html"><![CDATA[
      <p><a href="https://github.com/deseretbook/hashformer"><figure class="image half-right img-thumbnail"><img src="https://blog.mikebourgeous.com/images/2016/11/22/hashformer-transform-data-in-ruby/hashformer_on_github.png"  alt="Hashformer on GitHub"></figure></a></p>

<p>Let me tell you about <a href="https://github.com/deseretbook/hashformer">Hashformer</a>, another open source Ruby Gem I wrote for
my previous employer.  Like <a href="https://blog.mikebourgeous.com/2016/11/16/data-validation-in-ruby-with-classyhash/">ClassyHash</a>, Hashformer was written as part of
the &ldquo;middleware&rdquo; interface between a Solidus ecommerce site and an Oracle
E-business Suite backend.  Hashformer defines a Ruby <abbr
title="Domain-specific Language">DSL</abbr> for basic data transformations, like
renaming keys, merging values, etc.</p>

<p>Hashformer is a bit more niche than ClassyHash &mdash; most projects probably
wouldn&rsquo;t have a use for it, but when you need it, you need it.  It&rsquo;s similar in
spirit to that old four-letter word, XSLT, but simpler and Ruby-centric.  Read
on for an example.</p>


      <p><a href="https://blog.mikebourgeous.com/2016/11/22/hashformer-transform-data-in-ruby/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Data validation in Ruby with ClassyHash]]></title>
    <link href="https://blog.mikebourgeous.com/2016/11/16/data-validation-in-ruby-with-classyhash/"/>
    <updated>2016-11-16T18:33:10-07:00</updated>
    <id>https://blog.mikebourgeous.com/2016/11/16/data-validation-in-ruby-with-classyhash</id>
    <content type="html"><![CDATA[
      <p>In this post I will briefly demonstrate the <a href="https://github.com/deseretbook/classy_hash">ClassyHash</a> gem, which is a fast
data validation gem written in pure Ruby.  I recently released <a href="https://rubygems.org/gems/classy_hash/versions/0.2.0">version 0.2.0 of
ClassyHash</a>, with some cool PRs integrated and quite a few new features.
Here&rsquo;s a quick example:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">schema</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>  <span class="ss">query</span><span class="p">:</span> <span class="no">Set</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;repo&#39;</span><span class="p">,</span> <span class="s1">&#39;user&#39;</span><span class="p">),</span> <span class="c1"># Match either &#39;repo&#39; or &#39;user&#39;</span>
</span><span class='line'>  <span class="ss">values</span><span class="p">:</span> <span class="o">[[</span><span class="nb">String</span><span class="o">]]</span><span class="p">,</span> <span class="c1"># Match an array of zero or more Strings</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>  <span class="ss">query</span><span class="p">:</span> <span class="s1">&#39;repo&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="ss">values</span><span class="p">:</span> <span class="o">[</span><span class="s1">&#39;classy_hash&#39;</span><span class="p">,</span> <span class="s1">&#39;hashformer&#39;</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="no">CH</span><span class="o">.</span><span class="n">validate</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">schema</span><span class="p">)</span> <span class="c1"># Returns true if the data is valid, raises an error if not</span>
</span></code></pre></td></tr></table></div></figure>


<p>Continue reading to learn about ClassyHash&rsquo;s history and see a basic ClassyHash
validation tutorial.</p>


      <p><a href="https://blog.mikebourgeous.com/2016/11/16/data-validation-in-ruby-with-classyhash/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Resurrecting a dinosaur: the iBIZ KeySync keyboard for Pocket PC]]></title>
    <link href="https://blog.mikebourgeous.com/2016/11/09/resurrecting-a-dinosaur-the-ibiz-keysync-keyboard-for-pocket-pc/"/>
    <updated>2016-11-09T19:02:42-07:00</updated>
    <id>https://blog.mikebourgeous.com/2016/11/09/resurrecting-a-dinosaur-the-ibiz-keysync-keyboard-for-pocket-pc</id>
    <content type="html"><![CDATA[
      <p><figure class="image pull-left"><img src="https://blog.mikebourgeous.com/images/2016/11/09/resurrecting-a-dinosaur-the-ibiz-keysync-keyboard-for-pocket-pc/keysync_keyboard.jpg"></figure></p>

<p>Several years ago I came across a number of obsolete Pocket PC handhelds and
accessories at a surplus sale.  While the PocketPCs themselves weren&rsquo;t worth
keeping due to the dead batteries and slow processors, I held onto a compact
portable keyboard with a 9-pin serial connector made by a company called iBIZ.
I&rsquo;m finally getting around to hooking the keyboard up and seeing if I can get it
to work.  In this post I&rsquo;ll document the process of connecting to the iBIZ
KeySync keyboard and decoding its protocol.
      <p><a href="https://blog.mikebourgeous.com/2016/11/09/resurrecting-a-dinosaur-the-ibiz-keysync-keyboard-for-pocket-pc/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[New Blog Theme]]></title>
    <link href="https://blog.mikebourgeous.com/2016/10/28/new-blog-theme/"/>
    <updated>2016-10-28T18:09:50-06:00</updated>
    <id>https://blog.mikebourgeous.com/2016/10/28/new-blog-theme</id>
    <content type="html"><![CDATA[
      <p>If you&rsquo;ve come to my blog before, you may have noticed there&rsquo;s now a new site
design.  While Octopress is still awesome, my previous Octopress-based blog
theme wasn&rsquo;t a good match for the new design of <a href="http://www.mikebourgeous.com/">my main site</a>.
This updated design, using Bootstrap with some customizations, pays homage to
the original Octopress layout, but provides a more modern look and feel.</p>

<p>I&rsquo;m a desktop first kind of guy, and even I love the new theme on my mobile
devices.  I think you will too.  Continue reading to see a side-by-side
comparison of the old and new styles, and to see some of the other new tricks
of the upgraded theme.</p>


      <p><a href="https://blog.mikebourgeous.com/2016/10/28/new-blog-theme/">Read more...</a></p>
      ]]>
    </content>
  </entry>
  
</feed>
