<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet href="/feed_style.xsl" type="text/xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="https://www.rssboard.org/media-rss"><channel><title>Blerf</title><link>https://www.blerf.ca/</link><description>Recent content on Blerf</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>Sam Pillsworth - [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/)</copyright><lastBuildDate>Fri, 31 Oct 2025 22:50:00 -0400</lastBuildDate><atom:link href="https://www.blerf.ca/index.xml" rel="self" type="application/rss+xml"/><icon>https://www.blerf.ca/images/profile.png</icon><item><title>Fibonblerfi Part 2</title><link>https://www.blerf.ca/words/fibonblerfi-part2/</link><pubDate>Fri, 31 Oct 2025 22:50:00 -0400</pubDate><guid>https://www.blerf.ca/words/fibonblerfi-part2/</guid><description><![CDATA[<p>This is a refactor of the previous code example.
First, I took <a href="https://social.rossabaker.com/@ross/115466163662270864">Ross Baker&rsquo;s kind advice from his reply on Mastodon</a>.
But then I went down quite a rabbit hole as I followed my &ldquo;custom input type&rdquo; plan.</p>
<p>To start I created the <code>FibonacciNumber</code> struct, and started implementing <code>FromStr</code>. I struggled to implement the <code>Err</code> for the <code>Result</code> type at first, because I was trying to combine an <code>IntErrorKind::PosOverflow</code> (to be returned for numbers greater than 100) and a <code>ParseIntError</code>. I couldn&rsquo;t figure out how to limit my error enum to <strong>just</strong> the <code>PosOverflow</code> variant, the compiler kept telling me to use <code>IntErrorKind</code>. Eventually I gave up and just created my own variants. But once I had the enum it needed to be a proper <code>std::error::Error</code> which required implementing <code>Debug</code> (easy, because I could derive it) and <code>Display</code> (more toil but an easy enough pattern to follow).</p>
<p>I got momentarily distracted by the power of <code>Display</code> and implemented one for <code>FibonacciNumber</code> that gave each number the proper ordinal indicator. This was very satisfying.</p>
<p>Eventually I remembered the goal was <code>FromStr</code> and finished implementing that, returning either a <code>Ok(FibonacciNumber)</code> or an <code>Err(FibonacciNumberError)</code> in each branch.</p>
<p>The only nuance about using the <code>FibonacciNumber</code> was that I had to update my <code>fibonacci</code> function to borrow the number instead of moving it. I&rsquo;m still learning about ownership in Rust so I&rsquo;m not going to comment further on that other than to say: the compiler told me exactly what to do and I listened to it!</p>
<p>As previously: constructive feedback is much appreciated!</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span><span style="color:#c2ffdf">use</span><span style="color:#a8757b"> </span>std::{fmt::Display,<span style="color:#a8757b"> </span>io,<span style="color:#a8757b"> </span><span style="color:#c2ffdf">str</span>::FromStr};<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span><span style="color:#a8757b"></span><span style="color:#b0bec5">#[derive(Debug)]</span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">enum</span> <span style="color:#ceb1ff">FibonacciNumberError</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span><span style="color:#a8757b">    </span>TooBigError,<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span><span style="color:#a8757b">    </span>ParseError,<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">impl</span><span style="color:#a8757b"> </span>Display<span style="color:#a8757b"> </span><span style="color:#c2ffdf">for</span><span style="color:#a8757b"> </span>FibonacciNumberError<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">fn</span> <span style="color:#ceb1ff">fmt</span>(<span style="color:#ffb8d1">&amp;</span><span style="color:#80cbc4">self</span>,<span style="color:#a8757b"> </span>f: <span style="color:#c2ffdf">&amp;</span><span style="color:#ceb1ff">mut</span><span style="color:#a8757b"> </span>std::fmt::Formatter<span style="color:#ffb8d1">&lt;&#39;</span>_<span style="color:#ffb8d1">&gt;</span>)<span style="color:#a8757b"> </span>-&gt; <span style="color:#ceb1ff">std</span>::fmt::Result<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span><span style="color:#a8757b">        </span><span style="color:#c2ffdf">match</span><span style="color:#a8757b"> </span><span style="color:#80cbc4">self</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span><span style="color:#a8757b">            </span>FibonacciNumberError::TooBigError<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span><span style="color:#a8757b">                </span>write!(f,<span style="color:#a8757b"> </span><span style="color:#1bc5e0">&#34;Number must be a positive integer less than 101.&#34;</span>)<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span><span style="color:#a8757b">            </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span><span style="color:#a8757b">            </span>FibonacciNumberError::ParseError<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>write!(f,<span style="color:#a8757b"> </span><span style="color:#1bc5e0">&#34;Number must be a positive integer.&#34;</span>),<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span><span style="color:#a8757b">        </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span><span style="color:#a8757b">    </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">impl</span><span style="color:#a8757b"> </span>std::error::Error<span style="color:#a8757b"> </span><span style="color:#c2ffdf">for</span><span style="color:#a8757b"> </span>FibonacciNumberError<span style="color:#a8757b"> </span>{}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">struct</span> <span style="color:#ceb1ff">FibonacciNumber</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21</span><span><span style="color:#a8757b">    </span>n: <span style="color:#c2ffdf">u8</span>,<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">impl</span><span style="color:#a8757b"> </span>Display<span style="color:#a8757b"> </span><span style="color:#c2ffdf">for</span><span style="color:#a8757b"> </span>FibonacciNumber<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">fn</span> <span style="color:#ceb1ff">fmt</span>(<span style="color:#ffb8d1">&amp;</span><span style="color:#80cbc4">self</span>,<span style="color:#a8757b"> </span>f: <span style="color:#c2ffdf">&amp;</span><span style="color:#ceb1ff">mut</span><span style="color:#a8757b"> </span>std::fmt::Formatter<span style="color:#ffb8d1">&lt;&#39;</span>_<span style="color:#ffb8d1">&gt;</span>)<span style="color:#a8757b"> </span>-&gt; <span style="color:#ceb1ff">std</span>::fmt::Result<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25</span><span><span style="color:#a8757b">        </span><span style="color:#c2ffdf">if</span><span style="color:#a8757b"> </span>[<span style="color:#c5a3ff">11</span>,<span style="color:#a8757b"> </span><span style="color:#c5a3ff">12</span>,<span style="color:#a8757b"> </span><span style="color:#c5a3ff">13</span>].contains(<span style="color:#ffb8d1">&amp;</span><span style="color:#80cbc4">self</span>.n)<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26</span><span><span style="color:#a8757b">            </span>write!(f,<span style="color:#a8757b"> </span><span style="color:#1bc5e0">&#34;{}th&#34;</span>,<span style="color:#a8757b"> </span><span style="color:#80cbc4">self</span>.n)<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27</span><span><span style="color:#a8757b">        </span>}<span style="color:#a8757b"> </span><span style="color:#c2ffdf">else</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28</span><span><span style="color:#a8757b">            </span><span style="color:#c2ffdf">match</span><span style="color:#a8757b"> </span><span style="color:#80cbc4">self</span>.n<span style="color:#a8757b"> </span><span style="color:#ffb8d1">%</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">10</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29</span><span><span style="color:#a8757b">                </span><span style="color:#c5a3ff">1</span><span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>write!(f,<span style="color:#a8757b"> </span><span style="color:#1bc5e0">&#34;{}st&#34;</span>,<span style="color:#a8757b"> </span><span style="color:#80cbc4">self</span>.n),<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30</span><span><span style="color:#a8757b">                </span><span style="color:#c5a3ff">2</span><span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>write!(f,<span style="color:#a8757b"> </span><span style="color:#1bc5e0">&#34;{}nd&#34;</span>,<span style="color:#a8757b"> </span><span style="color:#80cbc4">self</span>.n),<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31</span><span><span style="color:#a8757b">                </span><span style="color:#c5a3ff">3</span><span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>write!(f,<span style="color:#a8757b"> </span><span style="color:#1bc5e0">&#34;{}rd&#34;</span>,<span style="color:#a8757b"> </span><span style="color:#80cbc4">self</span>.n),<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32</span><span><span style="color:#a8757b">                </span>_<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>write!(f,<span style="color:#a8757b"> </span><span style="color:#1bc5e0">&#34;{}th&#34;</span>,<span style="color:#a8757b"> </span><span style="color:#80cbc4">self</span>.n),<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33</span><span><span style="color:#a8757b">            </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34</span><span><span style="color:#a8757b">        </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35</span><span><span style="color:#a8757b">    </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">impl</span><span style="color:#a8757b"> </span>FromStr<span style="color:#a8757b"> </span><span style="color:#c2ffdf">for</span><span style="color:#a8757b"> </span>FibonacciNumber<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">type</span> Err <span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>FibonacciNumberError;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">fn</span> <span style="color:#ceb1ff">from_str</span>(s: <span style="color:#c2ffdf">&amp;</span><span style="color:#c2ffdf">str</span>)<span style="color:#a8757b"> </span>-&gt; Result<span style="color:#ffb8d1">&lt;</span><span style="color:#80cbc4">Self</span>,<span style="color:#a8757b"> </span><span style="color:#80cbc4">Self</span>::Err<span style="color:#ffb8d1">&gt;</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40</span><span><span style="color:#a8757b">        </span><span style="color:#c2ffdf">match</span><span style="color:#a8757b"> </span>s.trim().parse()<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41</span><span><span style="color:#a8757b">            </span>Ok(num)<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">42</span><span><span style="color:#a8757b">                </span><span style="color:#c2ffdf">if</span><span style="color:#a8757b"> </span>num<span style="color:#a8757b"> </span><span style="color:#ffb8d1">&gt;</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">100</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">43</span><span><span style="color:#a8757b">                    </span>Err(FibonacciNumberError::TooBigError)<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">44</span><span><span style="color:#a8757b">                </span>}<span style="color:#a8757b"> </span><span style="color:#c2ffdf">else</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">45</span><span><span style="color:#a8757b">                    </span>Ok(FibonacciNumber<span style="color:#a8757b"> </span>{<span style="color:#a8757b"> </span>n: <span style="color:#ceb1ff">num</span><span style="color:#a8757b"> </span>})<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">46</span><span><span style="color:#a8757b">                </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">47</span><span><span style="color:#a8757b">            </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">48</span><span><span style="color:#a8757b">            </span>Err(_)<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>Err(FibonacciNumberError::ParseError),<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">49</span><span><span style="color:#a8757b">        </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">50</span><span><span style="color:#a8757b">    </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">51</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">52</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">53</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">fn</span> <span style="color:#ceb1ff">main</span>()<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">54</span><span><span style="color:#a8757b">    </span>println!(<span style="color:#1bc5e0">&#34;Enter fibonacci number to generate.&#34;</span>);<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">55</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span>n: <span style="color:#ceb1ff">FibonacciNumber</span><span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">loop</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">56</span><span><span style="color:#a8757b">        </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>string_n<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>String::new();<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">57</span><span><span style="color:#a8757b">        </span>io::stdin()<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">58</span><span><span style="color:#a8757b">            </span>.read_line(<span style="color:#ffb8d1">&amp;</span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>string_n)<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">59</span><span><span style="color:#a8757b">            </span>.expect(<span style="color:#1bc5e0">&#34;Failed to read number!&#34;</span>);<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">60</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">61</span><span><span style="color:#a8757b">        </span><span style="color:#c2ffdf">match</span><span style="color:#a8757b"> </span>string_n.parse()<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">62</span><span><span style="color:#a8757b">            </span>Ok(num)<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">break</span><span style="color:#a8757b"> </span>num,<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">63</span><span><span style="color:#a8757b">            </span>Err(e)<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">64</span><span><span style="color:#a8757b">                </span>println!(<span style="color:#1bc5e0">&#34;{e}&#34;</span>);<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">65</span><span><span style="color:#a8757b">                </span><span style="color:#c2ffdf">continue</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">66</span><span><span style="color:#a8757b">            </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">67</span><span><span style="color:#a8757b">        </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">68</span><span><span style="color:#a8757b">    </span>};<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">69</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">70</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span>generated<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>fibonacci(<span style="color:#ffb8d1">&amp;</span>n);<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">71</span><span><span style="color:#a8757b">    </span>println!(<span style="color:#1bc5e0">&#34;The {n} fibonacci number is {generated}.&#34;</span>)<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">72</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">73</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">74</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">fn</span> <span style="color:#ceb1ff">fibonacci</span>(fib_num: <span style="color:#c2ffdf">&amp;</span><span style="color:#ceb1ff">FibonacciNumber</span>)<span style="color:#a8757b"> </span>-&gt; <span style="color:#c2ffdf">u128</span> {<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">75</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">match</span><span style="color:#a8757b"> </span>fib_num<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">76</span><span><span style="color:#a8757b">        </span>FibonacciNumber<span style="color:#a8757b"> </span>{<span style="color:#a8757b"> </span>n: <span style="color:#c5a3ff">0</span><span style="color:#a8757b"> </span>}<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">0</span>,<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">77</span><span><span style="color:#a8757b">        </span>_<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">78</span><span><span style="color:#a8757b">            </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>minus2: <span style="color:#c2ffdf">u128</span> <span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">0</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">79</span><span><span style="color:#a8757b">            </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>minus1: <span style="color:#c2ffdf">u128</span> <span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">80</span><span><span style="color:#a8757b">            </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>maybe_nth: <span style="color:#c2ffdf">u128</span> <span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">81</span><span><span style="color:#a8757b">            </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>counter<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>fib_num.n;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">82</span><span><span style="color:#a8757b">            </span><span style="color:#c2ffdf">while</span><span style="color:#a8757b"> </span>counter<span style="color:#a8757b"> </span><span style="color:#ffb8d1">&gt;</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">83</span><span><span style="color:#a8757b">                </span>maybe_nth<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>minus2<span style="color:#a8757b"> </span><span style="color:#ffb8d1">+</span><span style="color:#a8757b"> </span>minus1;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">84</span><span><span style="color:#a8757b">                </span>minus2<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>minus1;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">85</span><span><span style="color:#a8757b">                </span>minus1<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>maybe_nth;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">86</span><span><span style="color:#a8757b">                </span>counter<span style="color:#a8757b"> </span><span style="color:#ffb8d1">-=</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">87</span><span><span style="color:#a8757b">            </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">88</span><span><span style="color:#a8757b">            </span>maybe_nth<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">89</span><span><span style="color:#a8757b">        </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">90</span><span><span style="color:#a8757b">    </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">91</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span></code></pre></div>]]></description></item><item><title>Fibonblerfi</title><link>https://www.blerf.ca/words/fibonblerfi/</link><pubDate>Thu, 30 Oct 2025 17:53:00 -0400</pubDate><guid>https://www.blerf.ca/words/fibonblerfi/</guid><description><![CDATA[<p>I&rsquo;m learning Rust and as my first little thing I&rsquo;ve written a small script that
takes an input N and generates the corresponding Fibonacci number. The input is
limited to a <code>u8</code> that is 100 or less, and the output type is <code>u128</code> because
F<sub>100</sub> is a really big number. I would like to follow up with a version where I
implement my own input type with my own <code>parse</code> implementation that does the
bounds check.</p>
<p>The actual Fibonacci implementation feels a bit clunky, if only because I&rsquo;m so
used to reaching for tail recursion and I don&rsquo;t think I have that in Rust (there
is maybe a crate, but a lot of what I was reading was a few years old and the
current state was unclear and I got overwhelmed).</p>
<p>If anyone is so moved: I am very much a beginner on my Rust journey, and any
tips towards idiomatic Rust would be welcome.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span><span style="color:#c2ffdf">use</span><span style="color:#a8757b"> </span>std::io;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">fn</span> <span style="color:#ceb1ff">main</span>()<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span><span style="color:#a8757b">    </span>println!(<span style="color:#1bc5e0">&#34;Enter fibonacci number to generate.&#34;</span>);<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span>n: <span style="color:#c2ffdf">u8</span> <span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">loop</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span><span style="color:#a8757b">        </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>string_n<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>String::new();<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span><span style="color:#a8757b">        </span>io::stdin()<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span><span style="color:#a8757b">            </span>.read_line(<span style="color:#ffb8d1">&amp;</span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>string_n)<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span><span style="color:#a8757b">            </span>.expect(<span style="color:#1bc5e0">&#34;Failed to read number!&#34;</span>);<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span><span style="color:#a8757b">        </span><span style="color:#c2ffdf">match</span><span style="color:#a8757b"> </span>string_n.trim().parse()<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span><span style="color:#a8757b">            </span>Ok(num)<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span><span style="color:#a8757b">                </span><span style="color:#c2ffdf">if</span><span style="color:#a8757b"> </span>num<span style="color:#a8757b"> </span><span style="color:#ffb8d1">&gt;</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">100</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span><span style="color:#a8757b">                    </span>println!(<span style="color:#1bc5e0">&#34;Please enter a positive integer less than 101.&#34;</span>);<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span><span style="color:#a8757b">                    </span><span style="color:#c2ffdf">continue</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span><span style="color:#a8757b">                </span>}<span style="color:#a8757b"> </span><span style="color:#c2ffdf">else</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span><span style="color:#a8757b">                    </span><span style="color:#c2ffdf">break</span><span style="color:#a8757b"> </span>num;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18</span><span><span style="color:#a8757b">                </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19</span><span><span style="color:#a8757b">            </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20</span><span><span style="color:#a8757b">            </span>Err(_)<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21</span><span><span style="color:#a8757b">                </span>println!(<span style="color:#1bc5e0">&#34;Please enter a positive integer.&#34;</span>);<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22</span><span><span style="color:#a8757b">                </span><span style="color:#c2ffdf">continue</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23</span><span><span style="color:#a8757b">            </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24</span><span><span style="color:#a8757b">        </span>};<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25</span><span><span style="color:#a8757b">    </span>};<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span>generated<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">match</span><span style="color:#a8757b"> </span>n<span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28</span><span><span style="color:#a8757b">        </span><span style="color:#c5a3ff">0</span><span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">0</span>,<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29</span><span><span style="color:#a8757b">        </span><span style="color:#c5a3ff">1</span><span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span>,<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30</span><span><span style="color:#a8757b">        </span>_<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=&gt;</span><span style="color:#a8757b"> </span>fibonacci(n),<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31</span><span><span style="color:#a8757b">    </span>};<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33</span><span><span style="color:#a8757b">    </span>println!(<span style="color:#1bc5e0">&#34;The {n}th fibonacci number is {generated}!&#34;</span>)<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35</span><span><span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36</span><span><span style="color:#a8757b"></span><span style="color:#c2ffdf">fn</span> <span style="color:#ceb1ff">fibonacci</span>(n: <span style="color:#c2ffdf">u8</span>)<span style="color:#a8757b"> </span>-&gt; <span style="color:#c2ffdf">u128</span> {<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>minus2: <span style="color:#c2ffdf">u128</span> <span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">0</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>minus1: <span style="color:#c2ffdf">u128</span> <span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>maybe_nth: <span style="color:#c2ffdf">u128</span> <span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">let</span><span style="color:#a8757b"> </span><span style="color:#c2ffdf">mut</span><span style="color:#a8757b"> </span>counter<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>n;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41</span><span><span style="color:#a8757b">    </span><span style="color:#c2ffdf">while</span><span style="color:#a8757b"> </span>counter<span style="color:#a8757b"> </span><span style="color:#ffb8d1">&gt;</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span><span style="color:#a8757b"> </span>{<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">42</span><span><span style="color:#a8757b">        </span>maybe_nth<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>minus2<span style="color:#a8757b"> </span><span style="color:#ffb8d1">+</span><span style="color:#a8757b"> </span>minus1;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">43</span><span><span style="color:#a8757b">        </span>minus2<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>minus1;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">44</span><span><span style="color:#a8757b">        </span>minus1<span style="color:#a8757b"> </span><span style="color:#ffb8d1">=</span><span style="color:#a8757b"> </span>maybe_nth;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">45</span><span><span style="color:#a8757b">        </span>counter<span style="color:#a8757b"> </span><span style="color:#ffb8d1">-=</span><span style="color:#a8757b"> </span><span style="color:#c5a3ff">1</span>;<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">46</span><span><span style="color:#a8757b">        </span>println!(<span style="color:#1bc5e0">&#34;debug counter: {counter}, maybe_nth: {maybe_nth}&#34;</span>)<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">47</span><span><span style="color:#a8757b">    </span>}<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">48</span><span><span style="color:#a8757b">    </span>maybe_nth<span style="color:#a8757b">
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">49</span><span><span style="color:#a8757b"></span>}<span style="color:#a8757b">
</span></span></span></code></pre></div>]]></description></item><item><title>My plugin depends on WHAT?</title><link>https://www.blerf.ca/words/sbt-plugin-dependencies/</link><pubDate>Mon, 24 Feb 2025 12:51:00 -0500</pubDate><guid>https://www.blerf.ca/words/sbt-plugin-dependencies/</guid><description><![CDATA[<p>The Question: how do I know which sbt plugins are being brought in by this other sbt plugin in
my build?</p>
<p>This is something that comes up infrequently enough for me that I
always remember it&rsquo;s possible but infuriatingly can NEVER remember how to do it.
It&rsquo;s also really difficult to search for, so I spend a while feeling very frustrated
with sbt, the sbt plugin that has made me ask the question, and myself.</p>
<p>I&rsquo;m writing it down here in the hopes that I will remember I wrote it down, and have just one place on the internet to search!</p>
<p>The Steps:</p>
<ol>
<li>In an sbt console, run <code>reload plugins</code> to get into the root project&rsquo;s <code>project/</code> build definition.</li>
<li>Once in the project build, you can run a lot of your usual commands. For this particular problem, I run <code>dependencyBrowseTree</code> (from <code>sbt-dependency-tree</code> which I have defined as a global plugin) to open a searchable tree of all project dependencies.</li>
<li>Once finished, <code>reload return</code> switches you back to the original build.</li>
</ol>
<p>Pretty straightforward, just difficult to remember!</p>
]]></description></item><item><title>Mermaid diagrams on GitHub</title><link>https://www.blerf.ca/words/mermaid-config/</link><pubDate>Wed, 18 Sep 2024 09:32:00 -0400</pubDate><guid>https://www.blerf.ca/words/mermaid-config/</guid><description><![CDATA[<p>While working on a sequence diagram for a particular flow I lost a lot of time
trying to get a mermaid sequence diagram to not look chaotic, to not be so tiny
on my small laptop, and to have cute colours. I&rsquo;m saving this for future
reference.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span>---
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span>config:
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span>  theme: base
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span>  themeVariables:
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span>    textColor: &#34;#777&#34;
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>    primaryColor: &#34;#d33682&#34;
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span>    loopTextColor: &#34;#6c71c4&#34;
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span>    labelBoxBkgColor: &#34;#6c71c4&#34;
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span>    labelBoxBorderColor: &#34;#6c71c4&#34;
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span>  fontSize: 22
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span>---
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span>sequenceDiagram
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span>    participant A
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span>    participant B
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span>    participant C
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span>    A--&gt;&gt;+B: request to B
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span>    B--&gt;&gt;-A: response from B
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18</span><span>    A--&gt;&gt;+C: &lt;br/&gt;&lt;br/&gt;request to C
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19</span><span>    C--&gt;&gt;-A: response from C
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20</span><span>    par many requests in parallel
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21</span><span>    note right of B: remember!
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22</span><span>    B--&gt;&gt;+C: request to C
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23</span><span>    C--&gt;&gt;-B: response from C
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24</span><span>    end
</span></span></code></pre></div><h2 id="notes-about-this-config-in-no-particular-order">Notes about this config, in no particular order</h2>
<ul>
<li>I couldn&rsquo;t get <code>background</code> to work on GitHub to set a specific colour for the display window
<ul>
<li>This is why I had to set the font colour to a midtone grey, to try to support both a light and dark background</li>
</ul>
</li>
<li>the <code>&lt;br/&gt;&lt;br/&gt;</code> adds some visual space, so that a request and its response are clustered together compared to distinct requests</li>
<li>the <code>par</code> box &amp; border are controlled by the label variables, the action text is controlled by the loop text colour</li>
<li><code>fontSize</code> is changed at the top level, NOT inside the theme variables</li>
</ul>
<h2 id="screenshots">Screenshots</h2>
<p>This is what the above sequence diagram looks like in dark mode and light mode on GitHub:</p>
<figure><img src="/images/mermaid-config/dark-mode.png"/>
</figure>

<figure><img src="/images/mermaid-config/light-mode.png"/>
</figure>

]]></description></item><item><title>References</title><link>https://www.blerf.ca/words/references/</link><pubDate>Wed, 04 Sep 2024 19:53:00 -0400</pubDate><guid>https://www.blerf.ca/words/references/</guid><description><![CDATA[<p>This is just a collection of links for myself. Usually articles I&rsquo;ve referenced
or written about elsewhere and I want to keep some kind of track of them. For
now it&rsquo;s just a big list by year of access, but maybe I will better categorize
them some time in the future.</p>
<h2 id="2024">2024</h2>
<ul>
<li><a href="https://www.geoffreylitt.com/2024/08/25/your-pie-doesnt-need-be-original">https://www.geoffreylitt.com/2024/08/25/your-pie-doesnt-need-be-original</a></li>
<li><a href="https://www.ursulakleguin.com/a-rant-about-technology">https://www.ursulakleguin.com/a-rant-about-technology</a></li>
<li><a href="https://citiesandmemory.com/obsolete-sounds/">https://citiesandmemory.com/obsolete-sounds/</a></li>
</ul>
]]></description></item><item><title>Batch 'em up, Move 'em on</title><link>https://www.blerf.ca/words/batch-it/</link><pubDate>Wed, 28 Aug 2024 14:22:00 -0400</pubDate><guid>https://www.blerf.ca/words/batch-it/</guid><description><![CDATA[<p>I really like working with fs2. I like saving little code examples for myself. I
want to use the blog more and get out of the habit of reaching for gists. Also I need somewhere to put my intrusive-thought song parodies<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<h2 id="the-problem">The Problem</h2>
<p>We have a stream of &ldquo;things&rdquo;. We want to batch those things up, and do something
to each batch. We need to count which batch we&rsquo;re on. Oh and also, if the stream
of &ldquo;things&rdquo; is empty, we want to fallback to some other operation.</p>
<h2 id="the-code">The Code</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-scala" data-lang="scala"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span><span style="color:#c2ffdf">import</span> cats.effect.IO
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span><span style="color:#c2ffdf">import</span> fs2.Stream
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span><span style="color:#c2ffdf">def</span> getAndProcessThings<span style="color:#ffb8d1">(</span>batchSize<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Int</span><span style="color:#ffb8d1">)</span><span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span>  <span style="color:#c2ffdf">val</span> things<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Stream</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">String</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">Stream</span><span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">&#34;a&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;b&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;c&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;d&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;e&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;f&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;g&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;h&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;i&#34;</span><span style="color:#ffb8d1">,</span> <span style="color:#1bc5e0">&#34;j&#34;</span><span style="color:#ffb8d1">).</span>covary<span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">]</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>  <span style="color:#c2ffdf">val</span> fallback<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Stream</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">Stream</span><span style="color:#ffb8d1">.</span>eval<span style="color:#ffb8d1">(</span><span style="color:#ceb1ff">IO</span><span style="color:#ffb8d1">.</span>println<span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">&#34;falling back&#34;</span><span style="color:#ffb8d1">))</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span>  things
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span>    <span style="color:#ffb8d1">.</span>chunkN<span style="color:#ffb8d1">(</span>batchSize<span style="color:#ffb8d1">)</span> <span style="color:#b0bec5">// split stream into chunks of batchSize
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span><span style="color:#b0bec5"></span>    <span style="color:#ffb8d1">.</span>zipWithIndex <span style="color:#b0bec5">// zip the chunks together with an index
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span><span style="color:#b0bec5"></span>    <span style="color:#ffb8d1">.</span>evalMap <span style="color:#ffb8d1">{</span> <span style="color:#c2ffdf">case</span> <span style="color:#ffb8d1">(</span>chunk<span style="color:#ffb8d1">,</span> batchNumber<span style="color:#ffb8d1">)</span> <span style="color:#c2ffdf">=&gt;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span>      <span style="color:#ceb1ff">IO</span><span style="color:#ffb8d1">.</span>println<span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;Processing batch </span><span style="color:#1bc5e0">$batchNumber</span><span style="color:#1bc5e0">: </span><span style="color:#1bc5e0">$chunk</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span>    <span style="color:#ffb8d1">}</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span>    <span style="color:#ffb8d1">.</span>ifEmpty<span style="color:#ffb8d1">(</span>fallback<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span>    <span style="color:#ffb8d1">.</span>compile
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span>    <span style="color:#ffb8d1">.</span>drain
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span><span style="color:#ffb8d1">}</span>
</span></span></code></pre></div><p>If that function is run with a batch size of 3, we&rsquo;ll get the following output</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span>processing batch number 0; Chunk<span style="color:#ffb8d1">(</span>a, b, c<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span>processing batch number 1; Chunk<span style="color:#ffb8d1">(</span>d, e, f<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3</span><span>processing batch number 2; Chunk<span style="color:#ffb8d1">(</span>g, h, i<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4</span><span>processing batch number 3; Chunk<span style="color:#ffb8d1">(</span>j<span style="color:#ffb8d1">)</span>
</span></span></code></pre></div><p>If <code>things</code> was instead set to a value of <code>Stream.empty</code>, we&rsquo;ll instead see <code>falling back</code> printed.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Rawhidddeeeee&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description></item><item><title>About</title><link>https://www.blerf.ca/pages/about/</link><pubDate>Wed, 17 Jul 2024 00:00:00 +0000</pubDate><guid>https://www.blerf.ca/pages/about/</guid><description><![CDATA[<p><code>blerf</code> is a placeholder word. You use it when you need to use a word but the word itself does not matter. All my words are blerfs.</p>
<p>Blerf Inc. is also a company! You can hire me for various software engineering tasks, particularly where Scala is concerned. Reach out at <a href="mailto:admin@blerf.ca">admin@blerf.ca</a> to discuss.</p>
]]></description></item><item><title>Refs and Streams 2: Updating with an Endpoint</title><link>https://www.blerf.ca/words/refs-and-streams-2/</link><pubDate>Thu, 09 Feb 2023 11:05:00 -0500</pubDate><guid>https://www.blerf.ca/words/refs-and-streams-2/</guid><description><![CDATA[<p>Oh, hello. Lets continue with our <a href="https://www.blerf.ca/words/refs-and-streams-1/">ref and stream experiment</a> by writing and serving a minimal API
with <a href="https://http4s.org/">http4s</a>.</p>
<h2 id="the-problem-a-recap">The Problem, A Recap</h2>
<p>From the first post:</p>
<blockquote>
<p>We have some data, rows of recommendations. The data is stored on disk, and we want to write an API
that will return rows based on some query. The data, for now, is small enough that it can be read
into memory when we start the server. A different process will update the data on disk however, and
we need that update to propagate to the server without disrupting running requests. The update is
the piece I’ve been working on.</p>
</blockquote>
<p>I&rsquo;m continuing from last time by focusing now on the API:</p>
<ul>
<li>how to use the <code>Ref</code> to construct a response?</li>
<li>how to update the <code>Ref</code> via a request?</li>
<li>how to link the http4s <code>Server</code> with the scheduled updates?</li>
</ul>
<h2 id="the-pieces">The Pieces</h2>
<p>The method to update the <code>Ref</code> needed a few changes. The <code>prog</code> to do the actual updating is good;
however instead of running mulitple streams like in the previous example, we&rsquo;ll be using multiple
resources. So now I&rsquo;ve decided to compile the stream to a resource and return a <code>Resource[IO, Unit]</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-scala" data-lang="scala"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span><span style="color:#c2ffdf">def</span> scheduledUpdater<span style="color:#ffb8d1">(</span>ref<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Int</span><span style="color:#ffb8d1">])</span><span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Resource</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span>  <span style="color:#c2ffdf">val</span> prog <span style="color:#c2ffdf">=</span> ref
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3</span><span>    <span style="color:#ffb8d1">.</span>updateAndGet<span style="color:#ffb8d1">(</span>i <span style="color:#c2ffdf">=&gt;</span> i <span style="color:#ffb8d1">+</span> <span style="color:#c5a3ff">1</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4</span><span>    <span style="color:#ffb8d1">.</span>flatMap<span style="color:#ffb8d1">(</span>i <span style="color:#c2ffdf">=&gt;</span> <span style="color:#ceb1ff">IO</span><span style="color:#ffb8d1">.</span>println<span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;scheduled update: added 1, ref value is now </span><span style="color:#1bc5e0">$i</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">))</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5</span><span>  <span style="color:#ceb1ff">Stream</span><span style="color:#ffb8d1">.</span>repeatEval<span style="color:#ffb8d1">(</span>prog<span style="color:#ffb8d1">).</span>metered<span style="color:#ffb8d1">(</span><span style="color:#c5a3ff">1.</span>minute<span style="color:#ffb8d1">).</span>compile<span style="color:#ffb8d1">.</span>resource<span style="color:#ffb8d1">.</span>drain
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6</span><span><span style="color:#ffb8d1">}</span>
</span></span></code></pre></div><p>Instead of just printing the <code>Ref</code> value on a schedule, I wanted to make a curl request for the
current value. I also wanted to be able to set the value of the <code>Ref</code> arbitrarily via a request as
well. For that I wrote a 2-endpoint service:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-scala" data-lang="scala"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span><span style="color:#c2ffdf">def</span> refService<span style="color:#ffb8d1">(</span>ref<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Int</span><span style="color:#ffb8d1">])</span> <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">HttpRoutes</span><span style="color:#ffb8d1">.</span>of<span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">]</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span>  <span style="color:#c2ffdf">case</span> <span style="color:#ceb1ff">GET</span> <span style="color:#ffb8d1">-&gt;</span> <span style="color:#ceb1ff">Root</span> <span style="color:#ffb8d1">/</span> <span style="color:#1bc5e0">&#34;ref&#34;</span> <span style="color:#c2ffdf">=&gt;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span>    <span style="color:#c2ffdf">for</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span>      i    <span style="color:#c2ffdf">&lt;-</span> ref<span style="color:#ffb8d1">.</span>get
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span>      resp <span style="color:#c2ffdf">&lt;-</span> <span style="color:#ceb1ff">Ok</span><span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;Current ref value is: </span><span style="color:#1bc5e0">$i</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>    <span style="color:#ffb8d1">}</span> <span style="color:#c2ffdf">yield</span> resp
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span>  <span style="color:#c2ffdf">case</span> <span style="color:#ceb1ff">PUT</span> <span style="color:#ffb8d1">-&gt;</span> <span style="color:#ceb1ff">Root</span> <span style="color:#ffb8d1">/</span> <span style="color:#1bc5e0">&#34;ref&#34;</span> <span style="color:#ffb8d1">/</span> <span style="color:#ceb1ff">IntVar</span><span style="color:#ffb8d1">(</span>value<span style="color:#ffb8d1">)</span> <span style="color:#c2ffdf">=&gt;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span>    <span style="color:#c2ffdf">for</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span>      <span style="color:#c2ffdf">_</span>    <span style="color:#c2ffdf">&lt;-</span> ref<span style="color:#ffb8d1">.</span>set<span style="color:#ffb8d1">(</span>value<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span>      resp <span style="color:#c2ffdf">&lt;-</span> <span style="color:#ceb1ff">Ok</span><span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;Updated the ref value to: </span><span style="color:#1bc5e0">$value</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span>    <span style="color:#ffb8d1">}</span> <span style="color:#c2ffdf">yield</span> resp
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span><span style="color:#ffb8d1">}</span>
</span></span></code></pre></div><p>Finally, similar to last time, the tricky part was figuring out how to stitch the scheduled update
together with something else (in this case the <code>Server</code> resource). The real MVP here is the call to
<code>Resource.both</code>, which &ldquo;allocates two resources concurrently, and combines their results in a
tuple.&rdquo;<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> Then I can call <code>.useForever</code> on the tuple to have a forever-running server and
updater.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-scala" data-lang="scala"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span><span style="color:#c2ffdf">def</span> run<span style="color:#ffb8d1">(</span>args<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">List</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">String</span><span style="color:#ffb8d1">])</span><span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">ExitCode</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span>  <span style="color:#c2ffdf">val</span> serverAndUpdater<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Resource</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#ffb8d1">(</span><span style="color:#c2ffdf">Server</span>, <span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">)]</span> <span style="color:#c2ffdf">=</span> <span style="color:#c2ffdf">for</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span>    ref <span style="color:#c2ffdf">&lt;-</span> <span style="color:#ceb1ff">Resource</span><span style="color:#ffb8d1">.</span>eval<span style="color:#ffb8d1">(</span><span style="color:#ceb1ff">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">].</span>of<span style="color:#ffb8d1">(</span><span style="color:#c5a3ff">1</span><span style="color:#ffb8d1">))</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span>    httpApp <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">Router</span><span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">&#34;/&#34;</span> <span style="color:#ffb8d1">-&gt;</span> refService<span style="color:#ffb8d1">(</span>ref<span style="color:#ffb8d1">)).</span>orNotFound
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span>    updater <span style="color:#c2ffdf">=</span> scheduledUpdater<span style="color:#ffb8d1">(</span>ref<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>    server <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">EmberServerBuilder</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span>      <span style="color:#ffb8d1">.</span>default<span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">]</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span>      <span style="color:#ffb8d1">.</span>withHost<span style="color:#ffb8d1">(</span>ipv4<span style="color:#1bc5e0">&#34;0.0.0.0&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span>      <span style="color:#ffb8d1">.</span>withPort<span style="color:#ffb8d1">(</span>port<span style="color:#1bc5e0">&#34;8080&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span>      <span style="color:#ffb8d1">.</span>withHttpApp<span style="color:#ffb8d1">(</span>httpApp<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span>      <span style="color:#ffb8d1">.</span>build
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span>    serverAndUpdater <span style="color:#c2ffdf">&lt;-</span> <span style="color:#ceb1ff">Resource</span><span style="color:#ffb8d1">.</span>both<span style="color:#ffb8d1">(</span>server<span style="color:#ffb8d1">,</span> updater<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span>  <span style="color:#ffb8d1">}</span> <span style="color:#c2ffdf">yield</span> serverAndUpdater
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span>  serverAndUpdater<span style="color:#ffb8d1">.</span>useForever<span style="color:#ffb8d1">.</span>as<span style="color:#ffb8d1">(</span><span style="color:#ceb1ff">ExitCode</span><span style="color:#ffb8d1">.</span><span style="color:#ceb1ff">Success</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span><span style="color:#ffb8d1">}</span>
</span></span></code></pre></div><h2 id="all-the-code-together">All The Code Together</h2>
<p>All the pieces come together like so:<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-scala" data-lang="scala"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span><span style="color:#b0bec5">//&gt; using lib &#34;co.fs2::fs2-core:3.4.0&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span><span style="color:#b0bec5">//&gt; using lib &#34;org.typelevel::cats-effect:3.4.4&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span><span style="color:#b0bec5">//
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span><span style="color:#b0bec5">//&gt; using lib &#34;org.http4s::http4s-core:0.23.17&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span><span style="color:#b0bec5">//&gt; using lib &#34;org.http4s::http4s-dsl:0.23.17&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span><span style="color:#b0bec5">//&gt; using lib &#34;org.http4s::http4s-ember-server:0.23.17&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span><span style="color:#b0bec5">//&gt; using lib &#34;org.http4s::http4s-server:0.23.17&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span><span style="color:#b0bec5"></span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span><span style="color:#c2ffdf">import</span> fs2.Stream
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span><span style="color:#c2ffdf">import</span> cats.effect.IO
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span><span style="color:#c2ffdf">import</span> cats.effect.IOApp
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span><span style="color:#c2ffdf">import</span> scala.concurrent.duration._
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span><span style="color:#c2ffdf">import</span> cats.effect.kernel.Ref
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span><span style="color:#c2ffdf">import</span> org.http4s.HttpRoutes
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span><span style="color:#c2ffdf">import</span> org.http4s.dsl.io._
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span><span style="color:#c2ffdf">import</span> org.http4s.implicits._
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18</span><span><span style="color:#c2ffdf">import</span> org.http4s.server.Router
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19</span><span><span style="color:#c2ffdf">import</span> org.http4s.ember.server.EmberServerBuilder
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21</span><span><span style="color:#c2ffdf">import</span> com.comcast.ip4s._
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22</span><span><span style="color:#c2ffdf">import</span> cats.effect.ExitCode
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23</span><span><span style="color:#c2ffdf">import</span> cats.effect.kernel.Resource
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24</span><span><span style="color:#c2ffdf">import</span> org.http4s.server.Server
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26</span><span><span style="color:#c2ffdf">object</span> <span style="color:#ceb1ff">ScheduledEndpoint</span> <span style="color:#c2ffdf">extends</span> <span style="color:#ceb1ff">IOApp</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28</span><span>  <span style="color:#c2ffdf">def</span> refService<span style="color:#ffb8d1">(</span>ref<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Int</span><span style="color:#ffb8d1">])</span> <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">HttpRoutes</span><span style="color:#ffb8d1">.</span>of<span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">]</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29</span><span>    <span style="color:#c2ffdf">case</span> <span style="color:#ceb1ff">GET</span> <span style="color:#ffb8d1">-&gt;</span> <span style="color:#ceb1ff">Root</span> <span style="color:#ffb8d1">/</span> <span style="color:#1bc5e0">&#34;ref&#34;</span> <span style="color:#c2ffdf">=&gt;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30</span><span>      <span style="color:#c2ffdf">for</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31</span><span>        i    <span style="color:#c2ffdf">&lt;-</span> ref<span style="color:#ffb8d1">.</span>get
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32</span><span>        resp <span style="color:#c2ffdf">&lt;-</span> <span style="color:#ceb1ff">Ok</span><span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;Current ref value is: </span><span style="color:#1bc5e0">$i</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33</span><span>      <span style="color:#ffb8d1">}</span> <span style="color:#c2ffdf">yield</span> resp
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34</span><span>    <span style="color:#c2ffdf">case</span> <span style="color:#ceb1ff">PUT</span> <span style="color:#ffb8d1">-&gt;</span> <span style="color:#ceb1ff">Root</span> <span style="color:#ffb8d1">/</span> <span style="color:#1bc5e0">&#34;ref&#34;</span> <span style="color:#ffb8d1">/</span> <span style="color:#ceb1ff">IntVar</span><span style="color:#ffb8d1">(</span>value<span style="color:#ffb8d1">)</span> <span style="color:#c2ffdf">=&gt;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35</span><span>      <span style="color:#c2ffdf">for</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36</span><span>        <span style="color:#c2ffdf">_</span>    <span style="color:#c2ffdf">&lt;-</span> ref<span style="color:#ffb8d1">.</span>set<span style="color:#ffb8d1">(</span>value<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37</span><span>        resp <span style="color:#c2ffdf">&lt;-</span> <span style="color:#ceb1ff">Ok</span><span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;Updated the ref value to: </span><span style="color:#1bc5e0">$value</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38</span><span>      <span style="color:#ffb8d1">}</span> <span style="color:#c2ffdf">yield</span> resp
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39</span><span>  <span style="color:#ffb8d1">}</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41</span><span>  <span style="color:#c2ffdf">def</span> scheduledUpdater<span style="color:#ffb8d1">(</span>ref<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Int</span><span style="color:#ffb8d1">])</span><span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Resource</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">42</span><span>    <span style="color:#c2ffdf">val</span> prog <span style="color:#c2ffdf">=</span> ref
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">43</span><span>      <span style="color:#ffb8d1">.</span>updateAndGet<span style="color:#ffb8d1">(</span>i <span style="color:#c2ffdf">=&gt;</span> i <span style="color:#ffb8d1">+</span> <span style="color:#c5a3ff">1</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">44</span><span>      <span style="color:#ffb8d1">.</span>flatMap<span style="color:#ffb8d1">(</span>i <span style="color:#c2ffdf">=&gt;</span> <span style="color:#ceb1ff">IO</span><span style="color:#ffb8d1">.</span>println<span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;scheduled update: added 1, ref value is now </span><span style="color:#1bc5e0">$i</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">))</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">45</span><span>    <span style="color:#ceb1ff">Stream</span><span style="color:#ffb8d1">.</span>repeatEval<span style="color:#ffb8d1">(</span>prog<span style="color:#ffb8d1">).</span>metered<span style="color:#ffb8d1">(</span><span style="color:#c5a3ff">1.</span>minute<span style="color:#ffb8d1">).</span>compile<span style="color:#ffb8d1">.</span>resource<span style="color:#ffb8d1">.</span>drain
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">46</span><span>  <span style="color:#ffb8d1">}</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">47</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">48</span><span>  <span style="color:#c2ffdf">def</span> run<span style="color:#ffb8d1">(</span>args<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">List</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">String</span><span style="color:#ffb8d1">])</span><span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">ExitCode</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">49</span><span>    <span style="color:#c2ffdf">val</span> serverAndUpdater<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Resource</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#ffb8d1">(</span><span style="color:#c2ffdf">Server</span>, <span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">)]</span> <span style="color:#c2ffdf">=</span> <span style="color:#c2ffdf">for</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">50</span><span>      ref <span style="color:#c2ffdf">&lt;-</span> <span style="color:#ceb1ff">Resource</span><span style="color:#ffb8d1">.</span>eval<span style="color:#ffb8d1">(</span><span style="color:#ceb1ff">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">].</span>of<span style="color:#ffb8d1">(</span><span style="color:#c5a3ff">1</span><span style="color:#ffb8d1">))</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">51</span><span>      httpApp <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">Router</span><span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">&#34;/&#34;</span> <span style="color:#ffb8d1">-&gt;</span> refService<span style="color:#ffb8d1">(</span>ref<span style="color:#ffb8d1">)).</span>orNotFound
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">52</span><span>      updater <span style="color:#c2ffdf">=</span> scheduledUpdater<span style="color:#ffb8d1">(</span>ref<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">53</span><span>      server <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">EmberServerBuilder</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">54</span><span>        <span style="color:#ffb8d1">.</span>default<span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">]</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">55</span><span>        <span style="color:#ffb8d1">.</span>withHost<span style="color:#ffb8d1">(</span>ipv4<span style="color:#1bc5e0">&#34;0.0.0.0&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">56</span><span>        <span style="color:#ffb8d1">.</span>withPort<span style="color:#ffb8d1">(</span>port<span style="color:#1bc5e0">&#34;8080&#34;</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">57</span><span>        <span style="color:#ffb8d1">.</span>withHttpApp<span style="color:#ffb8d1">(</span>httpApp<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">58</span><span>        <span style="color:#ffb8d1">.</span>build
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">59</span><span>      serverAndUpdater <span style="color:#c2ffdf">&lt;-</span> <span style="color:#ceb1ff">Resource</span><span style="color:#ffb8d1">.</span>both<span style="color:#ffb8d1">(</span>server<span style="color:#ffb8d1">,</span> updater<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">60</span><span>    <span style="color:#ffb8d1">}</span> <span style="color:#c2ffdf">yield</span> serverAndUpdater
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">61</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">62</span><span>    serverAndUpdater<span style="color:#ffb8d1">.</span>useForever<span style="color:#ffb8d1">.</span>as<span style="color:#ffb8d1">(</span><span style="color:#ceb1ff">ExitCode</span><span style="color:#ffb8d1">.</span><span style="color:#ceb1ff">Success</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">63</span><span>  <span style="color:#ffb8d1">}</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">64</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">65</span><span><span style="color:#ffb8d1">}</span>
</span></span></code></pre></div><p>And with that running, I can curl for the current value of the ref:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span>❯ curl 0.0.0.0:8080/ref
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span>Current ref value is: 1%
</span></span></code></pre></div><p>Letting it sit and run for a while, I can see the ref getting updated:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span>scheduled update: added 1, ref value is now <span style="color:#c5a3ff">2</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span>scheduled update: added 1, ref value is now <span style="color:#c5a3ff">3</span>
</span></span></code></pre></div><p>I can get the updated ref value, and <code>PUT</code> a brand new value too:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span>❯ curl 0.0.0.0:8080/ref
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span>Current ref value is: 3%
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4</span><span>❯ curl -X PUT 0.0.0.0:8080/ref/42
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5</span><span>Updated the ref value to: 42%
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7</span><span>❯ curl 0.0.0.0:8080/ref
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">8</span><span>Current ref value is: 42%
</span></span></code></pre></div><p>Neat! At <code>$work</code>, the update function was a lot more complicated because it was a streaming request to read from a
GCS bucket (and a lot of error handling to go with it), and the lookup was more complicated because
we have more than just an integer. BUT the bones of this solution are what I&rsquo;ve shipped and it&rsquo;s
going pretty well (touch wood, throw some salt over your left shoulder, etc. etc.).</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Check out the <a href="https://typelevel.org/cats-effect/api/3.x/cats/effect/kernel/Resource.html">API docs</a> (which I&rsquo;m quoting) for more details&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>As before, this code is available as <a href="https://gist.github.com/samspills/5a59db10a7d1b7b349fafae14cf42c3a">a gist</a>. You can run it directly using <a href="https://scala-cli.virtuslab.org/">scala-cli</a>.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description></item><item><title>Refs and Streams 1: Scheduling Updates</title><link>https://www.blerf.ca/words/refs-and-streams-1/</link><pubDate>Wed, 01 Feb 2023 20:09:00 -0500</pubDate><guid>https://www.blerf.ca/words/refs-and-streams-1/</guid><description><![CDATA[<p>The past month at <code>$work</code> I&rsquo;ve been working on a fun little problem, and I decided to minimize
it down as a future example for myself. This is part one of two parts.</p>
<h2 id="the-problem">The Problem</h2>
<p>We have some data, rows of recommendations. The data is stored on disk, and we want to write an API
that will return rows based on some query. The data, for now, is small enough that it can be read
into memory when we start the server. A different process will update the data on disk however, and
we need that update to propagate to the server without disrupting running requests. The update is
the piece I&rsquo;ve been working on.</p>
<h2 id="the-code">The Code</h2>
<p>I took this as an opportunity to build my understanding of <a href="https://typelevel.org/cats-effect/docs/std/ref">Cats Effect <code>Ref</code></a>, since it &ldquo;provides
safe concurrent access and modification of its content.&rdquo; I also wanted to use an
<a href="https://fs2.io/#/">fs2</a> <code>Stream</code> to handle the scheduling task (mostly because I know the fs2
stream API reasonably well and I could see how to do it. I&rsquo;m not sure if there is a better way to do
that piece.).</p>
<p>To start I defined a &ldquo;simpler&rdquo; version of my problem:</p>
<ul>
<li>suppose I have a single <code>Ref</code>, in IO, with an integer value</li>
<li>I want to print the value every second</li>
<li>I want to add 1 to the value every 3 seconds</li>
</ul>
<p>The implementation<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> for this reduced problem looks like so:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-scala" data-lang="scala"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span><span style="color:#b0bec5">//&gt; using lib &#34;co.fs2::fs2-core:3.4.0&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span><span style="color:#b0bec5">//&gt; using lib &#34;org.typelevel::cats-effect:3.4.4&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span><span style="color:#b0bec5"></span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span><span style="color:#c2ffdf">import</span> fs2.Stream
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span><span style="color:#c2ffdf">import</span> cats.effect.IO
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span><span style="color:#c2ffdf">import</span> cats.effect.IOApp
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span><span style="color:#c2ffdf">import</span> scala.concurrent.duration._
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span><span style="color:#c2ffdf">import</span> cats.effect.kernel.Ref
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span><span style="color:#c2ffdf">object</span> <span style="color:#ceb1ff">Scheduled</span> <span style="color:#c2ffdf">extends</span> <span style="color:#ceb1ff">IOApp</span><span style="color:#ffb8d1">.</span><span style="color:#ceb1ff">Simple</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span>  <span style="color:#c2ffdf">val</span> theRefThing<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Int</span><span style="color:#ffb8d1">]]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ceb1ff">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">].</span>of<span style="color:#ffb8d1">(</span><span style="color:#c5a3ff">1</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span>  <span style="color:#c2ffdf">def</span> scheduledUpdate<span style="color:#ffb8d1">(</span>ref<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Int</span><span style="color:#ffb8d1">])</span><span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Stream</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span>    <span style="color:#c2ffdf">val</span> prog <span style="color:#c2ffdf">=</span> ref
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span>      <span style="color:#ffb8d1">.</span>updateAndGet<span style="color:#ffb8d1">(</span>int <span style="color:#c2ffdf">=&gt;</span> int <span style="color:#ffb8d1">+</span> <span style="color:#c5a3ff">1</span><span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span>      <span style="color:#ffb8d1">.</span>flatMap<span style="color:#ffb8d1">(</span>int <span style="color:#c2ffdf">=&gt;</span> <span style="color:#ceb1ff">IO</span><span style="color:#ffb8d1">.</span>println<span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;updated the ref to </span><span style="color:#1bc5e0">$int</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">))</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span>    <span style="color:#ceb1ff">Stream</span><span style="color:#ffb8d1">.</span>repeatEval<span style="color:#ffb8d1">(</span>prog<span style="color:#ffb8d1">).</span>metered<span style="color:#ffb8d1">(</span><span style="color:#c5a3ff">3.</span>seconds<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18</span><span>  <span style="color:#ffb8d1">}</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20</span><span>  <span style="color:#c2ffdf">def</span> printRefThing<span style="color:#ffb8d1">(</span>ref<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Ref</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Int</span><span style="color:#ffb8d1">])</span><span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Stream</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">IO</span>, <span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> <span style="color:#ffb8d1">{</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21</span><span>    <span style="color:#c2ffdf">val</span> prog <span style="color:#c2ffdf">=</span> ref<span style="color:#ffb8d1">.</span>get
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22</span><span>      <span style="color:#ffb8d1">.</span>flatMap<span style="color:#ffb8d1">(</span>int <span style="color:#c2ffdf">=&gt;</span> <span style="color:#ceb1ff">IO</span><span style="color:#ffb8d1">.</span>println<span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;the current ref value is </span><span style="color:#1bc5e0">${</span>int<span style="color:#1bc5e0">}</span><span style="color:#1bc5e0">&#34;</span><span style="color:#ffb8d1">))</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23</span><span>    <span style="color:#ceb1ff">Stream</span><span style="color:#ffb8d1">.</span>repeatEval<span style="color:#ffb8d1">(</span>prog<span style="color:#ffb8d1">).</span>metered<span style="color:#ffb8d1">(</span><span style="color:#c5a3ff">1.</span>second<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24</span><span>  <span style="color:#ffb8d1">}</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26</span><span>  <span style="color:#c2ffdf">def</span> run<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">IO</span><span style="color:#ffb8d1">[</span><span style="color:#c2ffdf">Unit</span><span style="color:#ffb8d1">]</span> <span style="color:#c2ffdf">=</span> theRefThing<span style="color:#ffb8d1">.</span>flatMap<span style="color:#ffb8d1">(</span>ref <span style="color:#c2ffdf">=&gt;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27</span><span>    printRefThing<span style="color:#ffb8d1">(</span>ref<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28</span><span>      <span style="color:#ffb8d1">.</span>concurrently<span style="color:#ffb8d1">(</span>scheduledUpdate<span style="color:#ffb8d1">(</span>ref<span style="color:#ffb8d1">))</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29</span><span>      <span style="color:#ffb8d1">.</span>interruptAfter<span style="color:#ffb8d1">(</span><span style="color:#c5a3ff">10.</span>seconds<span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30</span><span>      <span style="color:#ffb8d1">.</span>compile
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31</span><span>      <span style="color:#ffb8d1">.</span>drain
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32</span><span>  <span style="color:#ffb8d1">)</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33</span><span><span style="color:#ffb8d1">}</span>
</span></span></code></pre></div><p>The <code>scheduledUpdate</code> and <code>printRefThing</code> methods both take in the ref as an argument. The
scheduling (printing every 1 second, or updating every 3 seconds) is handled by metering the
streams.</p>
<p>The entire experiment is orchestrated together in the <code>run</code> method, by creating <code>theRefThing</code>
<strong>once</strong>, and passing that same value to both methods. Those methods are run concurrently and
interrupted after 10 seconds.</p>
<p>I emphasize <strong>once</strong> because in the moment (and in the haze of the holidays<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>) I struggled here.
If I passed that initial <code>IO</code> around directly, then both streams would create a <code>Ref</code> each time
their respective programs ran. Both methods needs to be using the same <code>Ref</code> for any of this to
work.</p>
<p>The next step, which I&rsquo;ll write up separately, expands this reduced problem to include the API piece
(using <a href="https://http4s.org/">http4s</a>).</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>This code sample is also available as <a href="https://gist.github.com/samspills/b1a3434e1bac21ac9c62004df2f25306">a gist</a>. You can run it directly using <a href="https://scala-cli.virtuslab.org/">scala-cli</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>I didn&rsquo;t touch a computer for three whole weeks and it was glorious. I think my brain must
have assumed I&rsquo;d given up on tech and flushed my memory, because when I got back
to work I could barely <code>println(&quot;Hello, world&quot;)</code>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description></item><item><title>I blerfed it</title><link>https://www.blerf.ca/words/blerfed-it/</link><pubDate>Mon, 23 Jan 2023 23:23:00 -0500</pubDate><guid>https://www.blerf.ca/words/blerfed-it/</guid><description><![CDATA[<p>What&rsquo;s up nerds<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, I&rsquo;m back. Trying to figure this whole situation out.
To figure out:</p>
<ul>
<li><input checked="" disabled="" type="checkbox"> is this post getting generated?</li>
<li><input checked="" disabled="" type="checkbox"> how to make a footnote?</li>
<li><input checked="" disabled="" type="checkbox"> What do these checkboxes look like?
<ul>
<li>they look totally reasonable</li>
</ul>
</li>
<li><input checked="" disabled="" type="checkbox"> Did I figure out syntax highlighting?
<ul>
<li>hot damn I did! Good job Past Sam!</li>
</ul>
</li>
<li><input checked="" disabled="" type="checkbox"> different code styling?</li>
<li><input checked="" disabled="" type="checkbox"> line numbers??</li>
</ul>
<p>I am looking at this on a small screen and it looks not great. I think I would like to experiment
with different themes that are better layouts on a small screen.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#433e56;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-scala" data-lang="scala"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span><span style="color:#b0bec5">// this is just some sample code to check highlighting
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span><span style="color:#b0bec5"></span><span style="color:#c2ffdf">def</span> blerf<span style="color:#ffb8d1">(</span>name<span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">String</span><span style="color:#ffb8d1">)</span><span style="color:#c2ffdf">:</span> <span style="color:#c2ffdf">Unit</span> <span style="color:#ffb8d1">=</span> println<span style="color:#ffb8d1">(</span><span style="color:#1bc5e0">s&#34;Hey, </span><span style="color:#1bc5e0">${</span>name<span style="color:#1bc5e0">}</span><span style="color:#1bc5e0">, did you know that Sam blerfed it?&#34;</span><span style="color:#ffb8d1">)</span>
</span></span></code></pre></div><h2 id="to-remember-in-the-future">To remember in the future</h2>
<ul>
<li>If the netlify preview build fails but everything works locally, check the hugo version</li>
<li>not all chromastyles are available it seems?</li>
<li>the leading slashes for the logo paths are important</li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>It&rsquo;s me. My past self is nerds.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description></item><item><title>Blerf: An Introduction</title><link>https://www.blerf.ca/words/first-post/</link><pubDate>Sun, 20 Dec 2020 13:32:49 -0500</pubDate><guid>https://www.blerf.ca/words/first-post/</guid><description><![CDATA[<p>Oh hello. This is the first blerf, of what are presumably many blerfs to come, on Blerf. This post is mostly to serve as a debugging post for content layout in this Hugo theme (which I&rsquo;m not familiar with), but I&rsquo;m also putting some notes for myself here and they might be useful to the general public even.</p>
<h2 id="hugo-things">Hugo Things</h2>
<p>It seems that the internet assumes I know things about Hugo while learning about Netlify. Obviously that is not the case so here are some notes about what some of the suggested hugo commands and flags mean.</p>
<h3 id="--gc"><code>--gc</code></h3>
<p>Enables some cleanup tasks that will run after the build. I&rsquo;m assuming it stands for garbage collection.</p>
<h3 id="--minify"><code>--minify</code></h3>
<p>Enables minification of assets. Docs and other resources don&rsquo;t exactly describe what &ldquo;minification&rdquo; means so I&rsquo;m relying on my onomatopoetic interpretation here. I&rsquo;m also currently assuming that there aren&rsquo;t any technical choices to make about how assets are &ldquo;minified&rdquo;.</p>
<h3 id="--buildfuture"><code>--buildFuture</code></h3>
<p>Includes scheduled content (scheduling == setting a publish date to some time in the future?) in the build. I don&rsquo;t foresee ever being organized enough to schedule things but sure.</p>
<h3 id="--enablegitinfo"><code>--enableGitInfo</code></h3>
<p>Adds git rev, date, and author info to the pages. In my reading, I&rsquo;ve seen this flag specified only on the build command in the <code>context.split1</code> section of the <code>netlify.toml</code> file. My current un-educated best guess is that this is related to split testing, so that git info is included on the test pages? I highly doubt I&rsquo;ll be doing any kind of split testing so I don&rsquo;t know if I really need this? But also every example I&rsquo;ve looked at includes it sooooo maybe I&rsquo;m wrong and it&rsquo;s important. I won&rsquo;t delete but I don&rsquo;t like it.</p>
<h2 id="netlify-things">Netlify Things</h2>
<p>Most of Netlify configuration happens in the Netlify web gui (I think????). I guess I&rsquo;m about to find out aren&rsquo;t I?</p>
<h3 id="deploy_prime_url"><code>$DEPLOY_PRIME_URL</code></h3>
<p>Used in <code>netlify.toml</code>, references whatever is set as the primary domain in the site settings on Netlify. I believe that this parameter is only available within the <code>netlify.toml</code> file, it can&rsquo;t be referenced all willy-nilly.</p>
<h3 id="why-does-my-deployed-site-look-bad-but-my-preview-looks-good">why does my deployed site look bad but my preview looks good?</h3>
<p>This gave me a devil of a time, and I still don&rsquo;t understand why the deploy-preview worked but the production deploy didn&rsquo;t. There are some things I did that probably weren&rsquo;t the problem but are good to do anyway that I&rsquo;ve listed here. Ultimately I <em>think</em> the thing that kicked the system into gear was the CORS headers, but I&rsquo;m not sure.</p>
<ol>
<li>make sure the <code>baseUrl</code> in the <code>config.toml</code> matches the primary domain in Netlify</li>
<li>make sure the <code>baseUrl</code> in the <code>config.toml</code> uses <code>https</code> or else a lot of things get mad about mixed content</li>
<li>add a redirect from <code>/</code> to <code>/index.html</code> in <code>netlify.toml</code></li>
<li>add a headers block to enable CORS</li>
</ol>
]]></description></item></channel></rss>