<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Hacker News Personal Blogs 2022 | Top 100 Blogs</title><link>https://hn-blogs.kronis.dev/feed-top100.xml</link><description>A collection of blog posts from users of Hacker News, based on RSS feeds.</description><language>en-US</language><lastBuildDate>Wed, 20 May 2026 00:23:25 GMT</lastBuildDate><generator>rfeed v1.1.1</generator><docs>https://github.com/svpino/rfeed/blob/master/README.md</docs><item><title>Energy, Sustainability and Deployment Frequency</title><link>https://smcleod.net/2022/12/energy-sustainability-and-deployment-frequency/</link><description>&lt;!-- markdownlint-disable MD025 --&gt;
&lt;h1 id="deployment--delivery-frequency"&gt;Deployment / Delivery Frequency&lt;/h1&gt;
&lt;p&gt;I often end up needing to advocate for more frequent delivery/deployments with clients.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s the usual benefits commonly discussed such as improved feedback, reduced risk, well understood processes, maintainable dependencies etc&amp;hellip; however what&amp;rsquo;s often missed entirely is how it relates to the health and sustainability of the team.
&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Sat, 31 Dec 2022 03:03:41 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/12/energy-sustainability-and-deployment-frequency/</guid></item><item><title>2022 Year in Review</title><link>https://benovermyer.com/blog/2022/12/2022-year-in-review/</link><description>&lt;p&gt;2022 was a year of big changes. Some were foreseen and others came out of nowhere.&lt;/p&gt;
&lt;h2 id="40th-birthday-trip-to-hawai-i"&gt;40th birthday trip to Hawai'i&lt;/h2&gt;
&lt;p&gt;At the end of February, we went to Hawai'i for my 40th birthday. Our trip was exclusively to the Big Island. We stayed in three different places - a small Bali-themed apartment, a treehouse in the rainforest, and a resort hotel. The treehouse was definitely both the scariest and the most interesting. I say "scariest" because the bottom floor was open and there's a ton of wildlife, including wild pigs. However, it was gorgeous. I would stay there again.&lt;/p&gt;
&lt;p&gt;We went on a tour of a coffee plantation. I gained a newfound appreciation for Kona coffee because of that. Sadly, it's hard to get locally here in North Carolina. We also went to some interesting restaurants. My favorite was a sushi restaurant with only three tables that I managed to get a reservation at, despite reservations being hard to come by.&lt;/p&gt;
&lt;p&gt;One day when we were staying at the treehouse we went to see a big volcano. It was gorgeous, and the walk was fun. We got a lot of great photos from the trip, and some of the volcano shots were among the best.&lt;/p&gt;
&lt;h2 id="moving-to-wilmington-north-carolina"&gt;Moving to Wilmington, North Carolina&lt;/h2&gt;
&lt;p&gt;In January, I spent the month in Wilmington, North Carolina looking for a place to rent. A few days into my stay at my boss's condo on the beach, I found the perfect house and got everything signed and sorted out. I moved out of the condo and into the completely empty house. I bought a few things - really, just enough to survive for the month. Sarah visited for a couple weeks to see the place and explore the area.&lt;/p&gt;
&lt;p&gt;Before Sarah visited, I'd had another panic attack in January - my second ever - and it made me nervous. Throughout the first half of 2022, I experienced symptoms that would be near to the start of a panic attack, but I'd learned how to stave them off.&lt;/p&gt;
&lt;p&gt;The month of February we spent getting everything ready to move, and taking that trip to Hawai'i.&lt;/p&gt;
&lt;p&gt;March was the month we moved from Minneapolis to Wilmington. We packed up the house, and then I took Mojave and Kalahari in my Seltos and drove to our new home. The cats didn't much care for the road trip - they spent the majority of it curled up together behind the center console. The drive took three days. I hope to never make such a long drive again, especially with cats in tow. Sarah drove down after the movers came and hauled away all of our stuff. This was the first time I had personally hired movers for an interstate move. It didn't go as well as I'd hoped, but it also didn't go as badly as I'd feared. The weirdest part was having to pay in cash instead of with a card.&lt;/p&gt;
&lt;p&gt;Over the course of the next month or so, we got unpacked and moved in. Exploring Wilmington was not as much of a priority as establishing a sense of normalcy. We didn't go to the beach as much as we perhaps should have this first year in Wilmington. However, I did bike to the beach twice after we got our bicycles. That's a 45 minute bike ride, which is the longest I've ever taken, I think. The climate here on the coast is a welcome change from Minneapolis, especially now in the cold months. As I write this it's 48 degrees Fahrenheit, with the expected high being 66. Not bad for December 30.&lt;/p&gt;
&lt;h2 id="iron-arachne"&gt;Iron Arachne&lt;/h2&gt;
&lt;p&gt;Iron Arachne saw a great many updates over the course of the year. In June, I launched a dungeon generator for it. That was a huge project that I'd never quite figured out before and I was pretty proud of what I'd built. It wasn't as full-featured as others around the web, but it was mine. Writing it required a ton of small subsystems like room layout and distributing keys and monsters and whatnot. I added a ton of new sentient species. I rewrote the word generation system from scratch, and added a utility generator to the site to help me come up with new seed patterns for the generator. The region generator, too, saw a bunch of changes - in particular, adding nearby regions, including vassal states; as well as making name set generation for it configurable.&lt;/p&gt;
&lt;p&gt;After awhile I noticed that the language generator in the code base wasn't complete and wasn't used anywhere. So, I started expanding that. It's not complete yet, and I haven't touched it in months. I intend to get back to it at some point, but it's not a priority. In November, I changed the build system to use Node.js 18, and then later in the month migrated it to Vite. At the end of November, I also moved all the navigation to a dedicated page. This change was a long time in coming and finally made the site usable on mobile.&lt;/p&gt;
&lt;p&gt;At the end of 2021, I wrote that I'd update the culture, heraldry, and region generators. Well, I didn't touch the culture generator much, other than to flesh out some details and swap out the religion generator for it. I did add new charges to the heraldry generator. The region generator really saw the bulk of the changes. In addition to the dungeon generator, I also added an AD&amp;amp;D 2e character generator. That was the first time I'd ever written a complex generator as the result of a poll. I don't think I'll do that again any time soon; I really prefer working on generators of my own interest. In January I'd added a DCC character generator. That was more fun.&lt;/p&gt;
&lt;p&gt;Finally, I moved the site from &lt;a href="https://www.netlify.com/" rel="external"&gt;Netlify&lt;/a&gt; to &lt;a href="https://vercel.com/" rel="external"&gt;Vercel&lt;/a&gt;, to give it a little more separation from my personal sites.&lt;/p&gt;
&lt;h2 id="updates-to-my-personal-website"&gt;Updates to my personal website&lt;/h2&gt;
&lt;p&gt;My personal website saw a number of expansions and design changes this year. I redesigned it a bit after learning more about minimal CSS. The whole thing is designed to be quick to load even on much older and slower hardware. I added several books to my "books read" list, several blog posts, a few recipes, and a handful of new knowledge base articles.&lt;/p&gt;
&lt;p&gt;I'm increasingly determined to make my site a proper storehouse of information and stories dear to me. It would be nice if someone out there found it useful, or at least interesting. Failing that, it's still useful to me.&lt;/p&gt;
&lt;h2 id="giving-up-alcohol"&gt;Giving up alcohol&lt;/h2&gt;
&lt;p&gt;Probably one of the biggest personal changes happened on November 10. Tired of all the negative effects of drinking, I finally gave it up completely. I had become accustomed to drinking every other night, sometimes six or more drinks. Going sober was much easier than I'd expected. The positive effects were much more noticeable than I expected, too. The most noticeable was how much more energy I had all the time after a couple weeks. Also, caffeine's effects on me changed. Instead of needing caffeine to properly function in the morning, now it makes me jittery if I have the same amount that I used to.&lt;/p&gt;
&lt;p&gt;I'm also dreaming again for the first time in years. Starting somewhere around 2015 or so, I stopped having dreams except only occasionally. Now I dream almost every night. They're the same kind of dreams I used to have - full of action and strangeness, like little movies that don't make a ton of sense. I'd forgotten how much fun they can be.&lt;/p&gt;
&lt;h2 id="from-individual-contributor-to-manager-to-tech-lead"&gt;From individual contributor to manager to tech lead&lt;/h2&gt;
&lt;p&gt;For a brief period early in the year, I was one of two new managers on the Platform Engineering team. However, the higher-ups felt that was unnecessary and a waste of our technical talents, so we got turned into tech leads instead.&lt;/p&gt;
&lt;p&gt;I don't handle any of the managerial duties, but I'm responsible for setting technical direction and leading standups. I didn't get a raise to go with the role change. My boss's boss assured me that was just because it fell outside the annual review cycle. I'm skeptical that I'll get a raise in the new year, though. While I make plenty, inflation means that if I don't get at least a raise matching the inflation rate, I'm actually getting a pay deduction each year. That feels kinda bad.&lt;/p&gt;
&lt;p&gt;Also, when the legacy (but stable) side of the business merged with the "startup" side that I'd originally joined, my duties changed. I'm working with a lot of legacy tech, including Perl applications. I don't like that at all. It feels like a bait-and-switch; I was hired to work on the latest tech and explore new horizons, but now most of my time is spent modernizing legacy systems and trying to figure out how to use modern tools with ancient technology.&lt;/p&gt;
&lt;p&gt;The pay and benefits are good, and I like the people I work with. However, I'm starting to feel stifled by some of the work, and I'm definitely not as engaged as I was before the merger.&lt;/p&gt;
&lt;h2 id="aws-re-invent-2022"&gt;AWS Re:invent 2022&lt;/h2&gt;
&lt;p&gt;The last time I went to Re:invent was 2016. The conference doubled in size; there was at least 60,000 people there this year. I tried to go to a dozen different sessions, but only got into one. I later made a presentation for my team about that session.&lt;/p&gt;
&lt;p&gt;Going sober definitely had a big impact on my Re:invent experience. At Re:invent in 2015 and 2016, I drank a &lt;em&gt;ton&lt;/em&gt; and went bar hopping with a bunch of strangers I met at the conference. This time around, I wasn't drinking at all, and a lot of the activities I used to enjoy seemed boring now. I also had a lot more energy for activities in the morning.&lt;/p&gt;
&lt;p&gt;Re:invent had special areas and swag for people with AWS certifications, so I used the half-off voucher they gave me beforehand to get certified. This was the first certification I'd ever paid for. It took a couple weeks of studying, but I passed the exam with flying colors and got my certification. It was a very strange experience, studying for an exam. I hadn't done that since university. I didn't care for it at all.&lt;/p&gt;
&lt;h2 id="end-of-my-boycott-of-blizzard"&gt;End of my boycott of Blizzard&lt;/h2&gt;
&lt;p&gt;I wrote at greater length about this &lt;a href="https://benovermyer.com/blog/2022/10/checking-back-in-on-blizzard/"&gt;earlier this year&lt;/a&gt;. Since that post, I've played a ton of Overwatch 2 and World of Warcraft. I didn't play much Diablo 2 and uninstalled it. I did preorder Diablo IV, despite the controversy surrounding its launch date. Blizzard is definitely still having problems. I don't think I'll boycott them again, as it had no material effect on anything. We'll see how things turn out. There's still the Microsoft acquisition to consider... if it goes through.&lt;/p&gt;
&lt;h2 id="silver-gryphon-games-comes-back"&gt;Silver Gryphon Games comes back&lt;/h2&gt;
&lt;p&gt;In August, Kevin and I made the decision to &lt;a href="https://www.silvergryphongames.com/2022/10/21/celebrate-with-us-as-silver-gryphon-games-returns/" rel="external"&gt;revive Silver Gryphon Games&lt;/a&gt;. This time around, though, I was the one to submit all the registration paperwork and manage the company side. I'm hoping that by being the driving force I can avoid the deliverables problems we had before. We committed to fulfilling the Aethermancy Kickstarter that we abandoned years ago. Also, I'm writing the new edition of Aether. This is the first time I've had an active hand in Aether. While I'm much more interested in writing OSR games, Aether reminds me a lot of what the Palladium System could have been if it was... well, good. For the first time in a long time, I'm really excited about writing for a commercial RPG. Kevin's working on Aethermancy while I work on Aether. He's heavily involved in his retail games business, though, so he's much more distracted than I am. Hopefully I can do right with Aether by him.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;This is by far my longest year-in-review post I've ever made. A ton happened in 2022. I imagine a lot is going to happen in 2023, too. Tomorrow I'll write about all my plans for the new year.&lt;/p&gt;
&lt;p&gt;Here's a list of all the year-in-review posts I've made. I have the strange sense that I've written more of these, but they're either lost to time, or in physical journals. I might have to try and find them if that's the case.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://benovermyer.com/blog/2021/12/2021-year-in-review/"&gt;2021&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benovermyer.com/blog/2020/12/2020-year-in-review/"&gt;2020&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benovermyer.com/blog/2018/12/2018-year-in-review/"&gt;2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benovermyer.com/blog/2017/01/looking-back-on-2016-and-forward-to-2017/"&gt;2016&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benovermyer.com/blog/2016/01/2015-year-in-review/"&gt;2015&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benovermyer.com/blog/2013/12/2013-year-in-review/"&gt;2013&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Ben Overmyer's Site</author><pubDate>Sat, 31 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/12/2022-year-in-review/</guid></item><item><title>Ranking #1 on HN in the December Dead Zone</title><link>https://www.swyx.io/lspace-2022</link><description>&lt;p&gt;For those who weren't aware (you would be if you were &lt;a href="https://lspace.swyx.io/subscribe?simple=true&amp;#x26;next=https://lspace.swyx.io/"&gt;subscribed&lt;/a&gt; on email!), I started a separate AI blog, &lt;a href="https://lspace.swyx.io/"&gt;L-space Diaries&lt;/a&gt;, this year to 1) try out Substack in anger and 2) create a focused feed on a topic rather than a person (I also started &lt;a href="https://dx.tips/"&gt;DX Tips&lt;/a&gt; for devtools/devrel writing, but have been accordingly distracted).&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Fri, 30 Dec 2022 02:50:58 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/lspace-2022</guid></item><item><title>2022: year in perspective</title><link>https://learnbyexample.github.io/2022-year-in-perspective/</link><description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Published two programming ebooks, wrote several blog posts, recorded plenty of Youtube videos, newsletter prospered, improved Twitter audience, read 100+ novels, and so on. Had an excellent year in terms of ebook sales 😇&lt;/p&gt;
&lt;span id="continue-reading"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h2 id="books-published"&gt;Books published&lt;a class="zola-anchor" href="#books-published"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; — concise learning resource for beginner to intermediate level Vim users, published in March&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/learnbyexample/cli-computing"&gt;Computing from the Command Line&lt;/a&gt; — Linux command line tools and Shell Scripting for beginner to intermediate level users, published in November&lt;/li&gt;
&lt;/ul&gt;
&lt;p align="center"&gt;&lt;img alt="Programming books published in 2022" src="/images/books/2022_books.png" /&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="workshops"&gt;Workshops&lt;a class="zola-anchor" href="#workshops"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Offline workshops were back on menu this year. I got only one offer though. Surprisingly, it was for Python basics, despite students already having had a course in their first year. It was a nice experience for me, thanks to the enthusiasm shown by the students.&lt;/p&gt;
&lt;p&gt;And it was good to see &lt;a href="https://barcampbangalore.com/bcb/"&gt;BarCamp Bangalore&lt;/a&gt; being organized again. Gave a talk about my ebook publishing experience (I had also written a &lt;a href="https://learnbyexample.github.io/my-book-writing-experience/"&gt;blog post&lt;/a&gt; on this topic last year).&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="blog-posts"&gt;Blog posts&lt;a class="zola-anchor" href="#blog-posts"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here are my favorite posts I wrote this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/interactive-linux-cli-exercises/"&gt;Interactive Linux CLI Text Processing Exercises&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/textual-first-impressions/"&gt;Building TUIs with textual: first impressions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/python-regex-possessive-quantifier/"&gt;Python 3.11: possessive quantifiers added to re module&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;came to know that this post &lt;a href="https://twitter.com/s_gruppetta_ct/status/1596097402381176832"&gt;ranks high during online searches&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/duplicates-irrespective-field-order/"&gt;Removing duplicates irrespective of field order&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I continued posting &lt;a href="https://learnbyexample.github.io/tips/"&gt;weekly programming tips&lt;/a&gt; (Python, Linux, Vim) that are short and easy to digest and wrote some &lt;a href="https://learnbyexample.github.io/mini/"&gt;mini blog posts&lt;/a&gt; as well.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="tools"&gt;Tools&lt;a class="zola-anchor" href="#tools"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During the last two months of the year, I learned a bit of &lt;a href="https://textual.textualize.io/"&gt;Textual&lt;/a&gt; and wrote a couple of TUI apps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/learnbyexample/TUI-apps/tree/main/SquareTicTacToe"&gt;Square Tic Tac Toe&lt;/a&gt; — form a square with 4 corners&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/learnbyexample/TUI-apps/tree/main/CLI-Exercises"&gt;Linux CLI Text Processing Exercises&lt;/a&gt; — test your CLI text processing skills&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found the framework much easier to use compared to my experience with Tkinter.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="youtube"&gt;Youtube&lt;a class="zola-anchor" href="#youtube"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While working on the Vim Reference Guide, I felt that some of the commands really needed video demos for easier understanding. So, I gave myself another chance at recording videos. I kept them simple and short, and with consistent practice I did better than my attempts a few years back. I then extended my new found enthusiasm to programming tips, ebook promo videos, etc. Visit my &lt;a href="https://www.youtube.com/c/learnbyexample42"&gt;youtube channel&lt;/a&gt; for interesting tech nuggets.&lt;/p&gt;
&lt;p&gt;Here are some of the tools I use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/MaartenBaert/ssr"&gt;SimpleScreenRecorder&lt;/a&gt; — recording video, really simple to use&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/WyattBlue/auto-editor"&gt;auto-editor&lt;/a&gt; — removing silent portions from video recordings&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/FFmpeg/FFmpeg"&gt;FFmpeg&lt;/a&gt; — video processing, padding for example (&lt;code&gt;FFmpeg&lt;/code&gt; is also a major part of the &lt;code&gt;auto-editor&lt;/code&gt; solution)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.canva.com/"&gt;Canva&lt;/a&gt; — video thumbnails (I also use this app for ebook covers)&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 id="book-sales"&gt;Book sales&lt;a class="zola-anchor" href="#book-sales"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Revenue from ebook sales were almost 50% higher than last year!! As I wrote in the &lt;a href="https://learnbyexample.github.io/wild-ride-2021/"&gt;2021 was a wild ride&lt;/a&gt; post, I've been paying more attention to marketing and seems like my efforts are paying off. Here's my Gumroad revenue chart for 2022:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Gumroad sales in 2022" src="/images/books/gumroad_sales_2022.png" /&gt;&lt;/p&gt;
&lt;p&gt;The peaks were during the two ebook releases. Additionally, I had less than half the above revenue from Leanpub. Last year, sales from Leanpub and Gumroad were nearly the same.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="newsletter"&gt;Newsletter&lt;a class="zola-anchor" href="#newsletter"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last November, I started &lt;a href="https://learnbyexample.gumroad.com/l/learnbyexample-weekly"&gt;learnbyexample weekly&lt;/a&gt; newsletter. I've managed to send an email every Friday without fail so far and I'm proud of that. Sometimes I had to schedule issues a week ahead. Currently about 600 subscribers and some readers are even paying me monthly despite being a free newsletter.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="building-twitter-audience"&gt;Building Twitter audience&lt;a class="zola-anchor" href="#building-twitter-audience"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As part of marketing efforts last year, I started building my Twitter audience as well. Follower count was less than 400 in July and about 1100 in December last year. Now it has crossed 2900. I'm not focused on increasing follower count with plethora of engagement inducing tweets. Just trying to be consistent and promoting all sorts of interesting links I come across. That said, I'd like to try creating cool infographics (probably using Canva) next year.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/learn_byexample"&gt;Follow me on Twitter&lt;/a&gt; for interesting tech nuggets 😉&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="fictional-reading"&gt;Fictional reading&lt;a class="zola-anchor" href="#fictional-reading"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I enjoy reading fantasy and science-fiction novels. I read 100+ SFF books this year and recently wrote a post listing &lt;a href="https://learnbyexample.github.io/escapist-reviews/lists/2022-favorite-sff-novels/"&gt;my favorites&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also got a chance to beta read &lt;a href="https://www.goodreads.com/book/show/60872852-tongue-eater"&gt;Tongue Eater&lt;/a&gt;, &lt;a href="https://www.goodreads.com/book/show/61324650-soul-relic"&gt;Soul Relic&lt;/a&gt;, &lt;a href="https://www.goodreads.com/book/show/60969058-the-umbral-storm"&gt;The Umbral Storm&lt;/a&gt; and &lt;a href="https://www.goodreads.com/book/show/62586822-the-book-of-zog"&gt;The Book of Zog&lt;/a&gt;. I find these a good way to give back to the writing community, having myself received plenty of support from strangers.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="goals-for-2023"&gt;Goals for 2023&lt;a class="zola-anchor" href="#goals-for-2023"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I met most of my goals this year, so that's a nice feeling. Contributing to open source projects needs a lot more focus in the coming year. I'm not likely to publish a &lt;em&gt;new&lt;/em&gt; ebook in 2023. Instead, I'm planning to update my existing books and that will probably take more than a year. Apart from catching up to new features and improving existing examples/exercises, I'll also focus on changing book titles and cover images. And, I'll likely create interactive apps for exercises.&lt;/p&gt;
&lt;p&gt;I need to also find something other than books to keep me creatively busy. It has been more than 4 years since I first published an ebook and 6 years since I started writing programming tutorials.&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;Here's wishing you a very happy, healthy and prosperous 2023 👍 😇&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 30 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/2022-year-in-perspective/</guid></item><item><title>Trouble with TypeScript Timeouts: How to Fix It</title><link>https://donatstudios.com/TypeScriptTimeoutTrouble</link><description>&lt;p&gt;The &lt;strong&gt;tl;dr&lt;/strong&gt; is this:&lt;/p&gt;
&lt;p&gt;You can fix the problem by replacing &lt;code&gt;number&lt;/code&gt; with &lt;code&gt;ReturnType&amp;lt;typeof setTimeout&amp;gt;&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;Similarly you can replace &lt;code&gt;number&lt;/code&gt; with &lt;code&gt;ReturnType&amp;lt;typeof setInterval&amp;gt;&lt;/code&gt; if you are seeing the problem with &lt;code&gt;setInterval&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you want to know more about it, read on.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I've run into this problem a number of times where I'm developing frontend TypeScript and after I import a package, I suddenly find throughout my project I'm receiving:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;error TS2322: Type 'Timeout' is not assignable to type 'number'.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are working on a Node project rather than a front end project this can also manifest itself as the opposite &lt;/p&gt;
&lt;pre&gt;&lt;code class="language-console"&gt;error TS2322: Type 'number' is not assignable to type 'Timeout'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usually this happens because some dependency included &lt;code&gt;@types/node&lt;/code&gt; under &lt;code&gt;dependencies&lt;/code&gt; instead of &lt;code&gt;devDependencies&lt;/code&gt;. When that happens, Node's global types leak into your project—even in frontend environments—causing &lt;code&gt;setTimeout&lt;/code&gt; to return a &lt;code&gt;Timeout&lt;/code&gt; object instead of a &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The heart of the problem is that &lt;code&gt;setTimeout()&lt;/code&gt; and &lt;code&gt;setInterval()&lt;/code&gt; in Node API return a &lt;code&gt;Timeout&lt;/code&gt; whereas in the HTML DOM Window API, they return an integer. &lt;/p&gt;
&lt;p&gt;The ideal solution would be for the offending package to &lt;em&gt;fix the problem&lt;/em&gt; themselves, and for you to update to the corrected version of the package. This is a hassle and might not be possible, with the issue going ignored for months if not years - as on Facebook's Jest package &lt;sup&gt;&lt;a href="https://github.com/facebook/jest/pull/12544"&gt;[1]&lt;/a&gt;&lt;/sup&gt; &lt;sup&gt;&lt;a href="https://github.com/facebook/jest/pull/13374"&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;For example, consider the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ts"&gt;let x : number = setTimeout(() =&amp;gt; console.log("foo"), 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your immediate reaction might be to either change the definition to &lt;code&gt;let x : Timeout&lt;/code&gt; or eliminate the explicit type definition all together à la&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ts"&gt;let x = setTimeout(() =&amp;gt; console.log("foo"), 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both of these options work.&lt;/p&gt;
&lt;p&gt;The first option of setting it to &lt;code&gt;Timeout&lt;/code&gt; suffers from two issues though. Firstly it's fragile - presumably you're not explicitly including &lt;code&gt;@types/node&lt;/code&gt; so the change to the environment is a side effect you're coding around. Should the specific packages you include change, or said package correct this it will break. Second, it's ambiguous. &lt;code&gt;Timeout&lt;/code&gt; isn’t a global type—it's specific to Node's type system—so using it assumes a Node environment even if you're working in the browser. That can confuse collaborators or tooling down the line.&lt;/p&gt;
&lt;p&gt;The second option of implicit typing will work in a lot of cases just fine. There are many cases where you'd want for instance to define the variable in a higher scope than you are setting its value - as a trivial example&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ts"&gt;class Foo {
    private x? : number;

    start() {
        this.x = setTimeout(() =&amp;gt; console.log("foo"), 1000);
    }

    stop() {
        clearTimeout(this.x);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The answer is frustratingly simple. We can just use the &lt;code&gt;ReturnType&lt;/code&gt; utility type to set our type to the return type of setTimeout. We can do this using &lt;code&gt;ReturnType&amp;lt;typeof setTimeout&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Our examples from above become&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ts"&gt;let x : ReturnType&amp;lt;typeof setTimeout&amp;gt; = setTimeout(() =&amp;gt; console.log("foo"), 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ts"&gt;class Foo {
    private x?: ReturnType&amp;lt;typeof setTimeout&amp;gt;;

    start() {
        this.x = setTimeout(() =&amp;gt; console.log("foo"), 1000);
    }

    stop() {
        clearTimeout(this.x);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, if you are using &lt;code&gt;setInterval&lt;/code&gt; you can utilize type &lt;code&gt;ReturnType&amp;lt;typeof setInterval&amp;gt;&lt;/code&gt; for similar purposes.&lt;/p&gt;</description><author>Donat Studios</author><pubDate>Wed, 28 Dec 2022 22:46:19 GMT</pubDate><guid isPermaLink="true">https://donatstudios.com/TypeScriptTimeoutTrouble</guid></item><item><title>Explore the fediverse, but use block like it's a machine gun in a zombie apocalypse</title><link>https://boyter.org/posts/mastinator-activitypub-breaking-assumptions/</link><description>&lt;p&gt;I didn&amp;rsquo;t really expect to have a post this late in the year but here we go. Lets go through some assumptions that were broken for me recently. Not just my own through perhaps some other peoples assumptions too.&lt;/p&gt;
&lt;p&gt;I have been working with ActivityPub for a bit. I want to run my own server, beyond installing some 3rd party. I want to build my own from scratch. However this rapidly exposed some problems with testing ActivityPub.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Wed, 28 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/mastinator-activitypub-breaking-assumptions/</guid></item><item><title>Python tip 21: sorting iterables based on a key</title><link>https://learnbyexample.github.io/tips/python-tip-21/</link><description>&lt;p&gt;You can use the &lt;code&gt;sort()&lt;/code&gt; method for sorting lists inplace. The &lt;code&gt;sorted()&lt;/code&gt; function can be used to get a sorted list from any iterable.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;key&lt;/code&gt; argument accepts the name of a function (i.e. function object) for custom sorting. If two elements are deemed equal based on the result of the function, the original order will be maintained (&lt;em&gt;stable sorting&lt;/em&gt;). Here are some examples:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #7f8989;"&gt;# based on the absolute value of an element
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# note that the input order is maintained for all three values of &amp;quot;4&amp;quot;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;309&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4.0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;34&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0.2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sort&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;key&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b39f04;"&gt;abs&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0.2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4.0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;34&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;309&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# based on the length of an element
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;words &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'morello'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'irk'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'fuliginous'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'crusado'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'seam'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;sorted&lt;/span&gt;&lt;span&gt;(words, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;key&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b39f04;"&gt;len&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;reverse&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'fuliginous'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'morello'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'crusado'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'seam'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'irk'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are some examples using &lt;a href="https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions"&gt;lambda expressions&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #7f8989;"&gt;# sorting dictionaries based on values
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;vehicles &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bus'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;20&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'jeep'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cycle'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;sorted&lt;/span&gt;&lt;span&gt;(vehicles, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;key&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=lambda &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;k&lt;/span&gt;&lt;span&gt;: vehicles[k])
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'jeep'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cycle'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bus'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;dict&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b39f04;"&gt;sorted&lt;/span&gt;&lt;span&gt;(vehicles.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;items&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;key&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=lambda &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;t&lt;/span&gt;&lt;span&gt;: t[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;]))
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'jeep'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cycle'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bus'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;20&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# based on file extension
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;files &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'report.txt'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'hello.py'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'calc.sh'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'tictactoe.py'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;sorted&lt;/span&gt;&lt;span&gt;(files, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;key&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=lambda &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;f&lt;/span&gt;&lt;span&gt;: f.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;rsplit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'.'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;)[&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;])
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'hello.py'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'tictactoe.py'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'calc.sh'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'report.txt'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also &lt;a href="https://docs.python.org/3/howto/sorting.html"&gt;docs.python HOWTOs: Sorting&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 28 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-21/</guid></item><item><title>Creepy Website Similarity</title><link>https://www.marginalia.nu/log/69-creepy-website-similarity/</link><description>&lt;p&gt;This is a write-up about an experiment from a few months ago, in how to find websites that are similar to each other. Website similarity is useful for many things, including discovering new websites to crawl, as well as suggesting similar websites in the Marginalia Search random exploration mode.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://explore2.marginalia.nu/"&gt;A link to a slapdash interface for exploring the experimental data.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The approach chosen was to use the link graph look for websites that are linked to from the same websites. This turned out to work remarkably well.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Mon, 26 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/69-creepy-website-similarity/</guid></item><item><title>Crypto I: On cryptocurrencies, explained using FTX Tokens</title><link>https://bytepawn.com/my-thoughts-on-crypto-explained-using-ftx-tokens.html</link><description>&lt;p&gt;The crypto space is a fascinating intersection of technology, economics and human psychology. However, I remain skeptical of the value of crypto tokens and NFTs. Here I explain my thought process using FTX Tokens as an example.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Crypto venn diagram" src="/images/crypto-venn.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 24 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/my-thoughts-on-crypto-explained-using-ftx-tokens.html</guid></item><item><title>On Wizards and Sorcerers</title><link>https://www.marginalia.nu/log/68-wizards-vs-sorcerers/</link><description>&lt;p&gt;While this post is about programming, it also draws an extended analogy to dungeons and dragons, specifically two of its classes, that correspond to two attitudes toward programming.&lt;/p&gt;
&lt;p&gt;In D&amp;amp;D, wizards study magic. They prepare their magic spells ahead of time. While they may learn a large number of magic spells, they need to prepare them ahead of time and can&amp;rsquo;t just cast them at will.&lt;/p&gt;
&lt;p&gt;Wizard programmers prefer up-front design. They apply reason and logic to divide and conquer a large problem, they rely on building blocks like design patterns and algorithms. Wizards rely on explicit knowledge.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Fri, 23 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/68-wizards-vs-sorcerers/</guid></item><item><title>Old School Baroque</title><link>https://benovermyer.com/blog/2022/12/old-school-baroque/</link><description>&lt;p&gt;Lately there have been an increasing number of new tabletop role-playing games coming out that are distinctly different from the Dungeons &amp;amp; Dragons retroclones popularized categorized as Old School Rennaissance or Old School Revival. These games eschew simplicity in favor of complex or complicated rules, and often have remarkable layout and design or gonzo themes. However, they still are directly influenced by rulesets and design themes from several decades ago. I think we can characterize these as "Old School Baroque."&lt;/p&gt;
&lt;p&gt;I did not coin this term. The first incidence I can find of it is on a &lt;a href="https://www.rpgpub.com/threads/principia-apocrypha-principles-of-old-school-rpgs.1891/#post-103320" rel="external"&gt;forum post on RPGPub in 2019&lt;/a&gt;. A more codified version of it appears in a more recent &lt;a href="https://traversefantasy.blogspot.com/2022/12/osr-rules-families.html" rel="external"&gt;blog article that carefully examines trends in OSR RPGs&lt;/a&gt;. While both the forum post and blog article use the term rather tongue-in-cheek, I think it's appropriate to describe this emerging category of games.&lt;/p&gt;
&lt;p&gt;The Baroque period of history was dramatic and a reaction to the Reformation. It leaned heavily into art and sensory exploration. The word "Baroque" is derived from the Italian "barocco" and is roughly equated to an abberation in or avoidance of logic. Where OSR games strive hard to adhere to the rules and themes of 70s and 80s Dungeons &amp;amp; Dragons, Old School Baroque games instead throw caution and tradition to the wind.&lt;/p&gt;
&lt;p&gt;One example of these games would be the much-vaunted &lt;a href="https://morkborg.com/" rel="external"&gt;Mörk Borg&lt;/a&gt;. The layout and design are heavily over-the-top and the game's setting is richly, even brutally, apocalyptic. It leans into a death metal aesthetic that cries out to the senses. The rules are clearly influenced by OSR games that came before it, but they're stretched and torn in ways that might offend more delicate OSR sensibilities. It is definitely more rules-light than other games in the Old School Baroque genre, though.&lt;/p&gt;
&lt;p&gt;Another game in this vein is &lt;a href="https://www.killjester.com/errant" rel="external"&gt;Errant&lt;/a&gt;, which presents itself as being "rules light, procedure heavy." That latter clause is what really makes it more of an OSB game than an OSR game. Well, that, and the hit-you-in-the-face aesthetic. While the aforementioned "procedures" are explicitly called out as not being rules, they are effectively rules in how to run the game. Even though Errant itself has a unified core mechanic, those procedures generally run all over the place.&lt;/p&gt;
&lt;p&gt;This is a fascinating new genre. I'm looking forward to watching its evolution.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Thu, 22 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/12/old-school-baroque/</guid></item><item><title>Announcing learnbyexample weekly newsletter</title><link>https://learnbyexample.github.io/learnbyexample-weekly-newsletter/</link><description>&lt;p&gt;Hello!&lt;/p&gt;
&lt;p&gt;I'm excited to announce &lt;a href="https://learnbyexample.gumroad.com/l/learnbyexample-weekly"&gt;learnbyexample weekly&lt;/a&gt; newsletter, scheduled to be delivered every Friday.&lt;/p&gt;
&lt;p&gt;This free newsletter will help you discover awesome programming resources. I'll primarily focus on resources related to Python, Linux, CLI tools, Regular Expressions and Vim. Sometimes, I'll also include other programming resources.&lt;/p&gt;
&lt;span id="continue-reading"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;p align="center"&gt;&lt;a href="https://learnbyexample.gumroad.com/l/learnbyexample-weekly"&gt;&lt;img alt="learnbyexample weekly newsletter" src="/images/learnbyexample-weekly.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;You can expect 5-15 links, usually categorized into the following sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Article of the week&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;li&gt;Free programming books, courses and deals&lt;/li&gt;
&lt;li&gt;Tip of the week&lt;/li&gt;
&lt;li&gt;Tools&lt;/li&gt;
&lt;li&gt;Curiosity Corner&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are some of the resource links from the first issue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.joshwcomeau.com/blog/how-to-learn-stuff-quickly/"&gt;How To Learn Stuff Quickly&lt;/a&gt; by Josh W. Comeau&lt;/li&gt;
&lt;li&gt;&lt;a href="https://miguendes.me/python-pathlib"&gt;Python pathlib Cookbook&lt;/a&gt; — 57+ Examples to Master It&lt;/li&gt;
&lt;li&gt;&lt;a href="https://shrutibalasa.gumroad.com/l/css-flex-and-grid/Newsoff25"&gt;Complete Guide to CSS Flex and Grid&lt;/a&gt; by Shruti Balasa (25% OFF for a week)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://carbon.now.sh/"&gt;Carbon&lt;/a&gt; — Create and share beautiful images of your source code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After subscribing to &lt;a href="https://learnbyexample.gumroad.com/l/learnbyexample-weekly"&gt;learnbyexample weekly&lt;/a&gt;, you'll get a confirmation email followed by another email with the latest issue contents. You can also view the past issues from your Gumroad account.&lt;/p&gt;
&lt;p&gt;Hope you find the newsletter useful. Let me know your feedback via email (learnbyexample.net@gmail.com) or &lt;a href="https://twitter.com/learn_byexample"&gt;twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy learning :)&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Thu, 22 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/learnbyexample-weekly-newsletter/</guid></item><item><title>The Indie Python Extravaganza</title><link>https://learnbyexample.github.io/indie-python-extravaganza/</link><description>&lt;p&gt;Hello!&lt;/p&gt;
&lt;p&gt;You never know where a conversation between indie authors will lead to. A &lt;a href="https://twitter.com/tw_lgiordani/status/1442489206681395207"&gt;tweet about Leanpub Python book sales&lt;/a&gt; brought up giveaways that we indie authors tend to do. Long story short, the four of us ended up deciding to create &lt;strong&gt;The Indie Python Extravaganza&lt;/strong&gt; bundle.&lt;/p&gt;
&lt;p&gt;And guess what?! You can use this &lt;a href="https://leanpub.com/b/theindiepythonextravaganza/c/pytober"&gt;pytober coupon link&lt;/a&gt; to get the bundle for FREE (the offer is valid till 31-Oct-2021).&lt;/p&gt;
&lt;span id="continue-reading"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h2 id="bundle-contents"&gt;Bundle contents&lt;a class="zola-anchor" href="#bundle-contents"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;A collection of books that will help you to improve your knowledge of the Python programming language one page at a time. Join four indie authors in a journey from the basics of Python to the structure of production-ready systems, going through the core features of the language, some intermediate projects and a deep dive into regular expressions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="center"&gt;&lt;img alt="The Indie Python Extravaganza cover image" src="/images/books/indie_python.jpg" /&gt;&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="https://leanpub.com/b/theindiepythonextravaganza/c/pytober"&gt;Coupon link&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In this bundle, Mike will teach you the basics of Python with &lt;strong&gt;Python 101&lt;/strong&gt;. Sundeep will then take the lead and help you to put your knowledge into practice with &lt;strong&gt;Practice Python Projects&lt;/strong&gt;. Learn what NOT to do when writing your Python programs with Rodrigo in his &lt;strong&gt;Pydon'ts&lt;/strong&gt; book! If you need to learn regular expressions, Sundeep has again your back with his &lt;strong&gt;Python re(gex)?&lt;/strong&gt; book, and when you are ready to start working on production code, you'll have &lt;strong&gt;Clean Architectures in Python&lt;/strong&gt; to help you!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
&lt;h2 id="authors"&gt;Authors&lt;a class="zola-anchor" href="#authors"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Leonardo Giordani: &lt;a href="https://www.thedigitalcatonline.com"&gt;Blog&lt;/a&gt;, &lt;a href="https://twitter.com/tw_lgiordani"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Michael Driscoll: &lt;a href="https://www.blog.pythonlibrary.org"&gt;Blog&lt;/a&gt;, &lt;a href="https://twitter.com/driscollis"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rodrigo Girão Serrão: &lt;a href="https://mathspp.com"&gt;Blog&lt;/a&gt;, &lt;a href="https://twitter.com/mathsppblog"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sundeep Agarwal: &lt;a href="https://learnbyexample.github.io/"&gt;Blog&lt;/a&gt;, &lt;a href="https://twitter.com/learn_byexample"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 id="how-can-you-help"&gt;How can you help?&lt;a class="zola-anchor" href="#how-can-you-help"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Share the bundle link with your friends and colleagues interested in learning Python.&lt;/p&gt;
&lt;p&gt;Your feedback on the book contents would be appreciated even more.&lt;/p&gt;
&lt;p&gt;Happy learning 😇&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Thu, 22 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/indie-python-extravaganza/</guid></item><item><title>Automating Excel with Python - book review</title><link>https://learnbyexample.github.io/automating-excel-with-python-review/</link><description>&lt;p&gt;In this post, I review &lt;strong&gt;Automating Excel with Python&lt;/strong&gt; by &lt;a href="https://www.blog.pythonlibrary.org/"&gt;Michael Driscoll&lt;/a&gt;. From the introduction chapter of this book:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The purpose of this book is to help you learn how to use Python to work with Excel. You will be using a package called OpenPyXL to create, read, and edit Excel documents with Python. While the focus of this book will be on OpenPyXL, you will also learn about other Python packages that you can use to interact with Excel using the Python programming language.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;span id="continue-reading"&gt;&lt;/span&gt;&lt;h2 id="book-details"&gt;Book details&lt;a class="zola-anchor" href="#book-details"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p align="center"&gt;&lt;img alt="Automating Excel with Python book cover" src="/images/automating_excel/automating_excel_with_python.jpg" /&gt;&lt;/p&gt;
&lt;p align="center"&gt;Book cover&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B09M5551W2"&gt;Amazon&lt;/a&gt; — Paperback, Kindle&lt;/li&gt;
&lt;li&gt;&lt;a href="https://driscollis.gumroad.com/l/openpyxl"&gt;Gumroad&lt;/a&gt; — PDF, EPUB, Mobi&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leanpub.com/openpyxl"&gt;Leanpub&lt;/a&gt; — PDF, EPUB, Mobi&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/driscollis/automating_excel_with_python"&gt;GitHub&lt;/a&gt; — code examples and sample spreadsheets used in the book&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/59974445-automating-excel-with-python"&gt;Goodreads&lt;/a&gt; — book reviews&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="review"&gt;Review&lt;a class="zola-anchor" href="#review"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My very first job assignment (at a semiconductor company) required me to use spreadsheets for tabulating results of various experiments, adding charts, etc. I used to manually copy-paste the results generated from a Perl script. There were multiple sheets and my work was complicated enough to require multiple months of refinement, feature modifications, etc. Not sure if a library like OpenPyXL existed back then, but I think I should've at least asked/searched ways to automate the spreadsheet process.&lt;/p&gt;
&lt;p&gt;Going through this book felt like someone wrote a book just for that project, albeit 13 years late. Here's a rough list of features that would've helped me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating &lt;code&gt;xlsx&lt;/code&gt; files with multiple sheets&lt;/li&gt;
&lt;li&gt;Adding data&lt;/li&gt;
&lt;li&gt;Formatting cells based on a known equation&lt;/li&gt;
&lt;li&gt;Creating charts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instructions and examples were clear and easy to follow. Snapshots were also shown for all the examples, so you can check if you've followed along as expected. While the book is best suited if you have MS Excel, most of the examples worked for me on LibreOffice Calc. Only the charts had major differences — some types weren't supported and x/y axis label/data were problematic as shown below:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Bar Chart in Excel" height="400px" src="/images/automating_excel/bar_chart_excel.png" width="600px" /&gt;&lt;/p&gt;
&lt;p align="center"&gt;Bar Chart in Excel (snapshot from the book)&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Bar Chart in Calc" height="400px" src="/images/automating_excel/bar_chart_calc.png" width="600px" /&gt;&lt;/p&gt;
&lt;p align="center"&gt;Bar Chart in LibreOffice Calc (what I got on my machine)&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;Apart from the &lt;code&gt;openpyxl&lt;/code&gt; module, the author also briefly covered how you can use &lt;code&gt;pandas&lt;/code&gt;, &lt;code&gt;xlsxwriter&lt;/code&gt; and &lt;code&gt;gspread&lt;/code&gt; (for working with Google sheets). Some features were presented at the end as Appendix chapters.&lt;/p&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="zola-anchor" href="#table-of-contents"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Chapter 1 - Setting Up Your Machine&lt;/li&gt;
&lt;li&gt;Chapter 2 - Reading Spreadsheets with OpenPyXL&lt;/li&gt;
&lt;li&gt;Chapter 3 - Creating a Spreadsheet with OpenPyXL&lt;/li&gt;
&lt;li&gt;Chapter 4 - Styling Cells&lt;/li&gt;
&lt;li&gt;Chapter 5 - Conditional Formatting&lt;/li&gt;
&lt;li&gt;Chapter 6 - Creating Charts&lt;/li&gt;
&lt;li&gt;Chapter 7 - Chart Types&lt;/li&gt;
&lt;li&gt;Chapter 8 - Converting CSV to Excel&lt;/li&gt;
&lt;li&gt;Chapter 9 - Using Pandas with Excel&lt;/li&gt;
&lt;li&gt;Chapter 10 - Python and Google Sheets&lt;/li&gt;
&lt;li&gt;Chapter 11 - XlsxWriter&lt;/li&gt;
&lt;li&gt;Appendix A - Cell Comments&lt;/li&gt;
&lt;li&gt;Appendix B - Print Settings Basics&lt;/li&gt;
&lt;li&gt;Appendix C - Formulas&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="feedback-and-reviews"&gt;Feedback and Reviews&lt;a class="zola-anchor" href="#feedback-and-reviews"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All in all, I would highly recommend this book for those wanting to use Python for automating spreadsheets. I'd request you to post reviews after going through the book (they help us indie authors a lot). And please do contact the author to let him know your feedback or if you have any clarifications.&lt;/p&gt;
&lt;p&gt;Happy learning :)&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 21 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/automating-excel-with-python-review/</guid></item><item><title>2021 was a wild ride</title><link>https://learnbyexample.github.io/wild-ride-2021/</link><description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Started and ended the year well, with a depressing period in the middle. Published three programming ebooks, several blog posts, started a newsletter, improved Twitter readership, read 80+ novels, and so on. Had a good year in terms of ebook sales 😇&lt;/p&gt;
&lt;span id="continue-reading"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h2 id="books-published"&gt;Books published&lt;a class="zola-anchor" href="#books-published"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; — short, introductory guide for the Python programming language. Started writing last year, published in February&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/learnbyexample/practice_python_projects"&gt;Practice Python Projects&lt;/a&gt; — five beginner to intermediate level projects inspired by real world use cases. Started writing last year (before &amp;quot;100 Page Python Intro&amp;quot;!), published in July&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/learnbyexample/cli_text_processing_coreutils"&gt;Command line text processing with GNU Coreutils&lt;/a&gt; — learn 20+ specialized text processing tools provided by the GNU coreutils package. Published in October&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also spent time updating all my existing books from February to May.&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Programming books published in 2021" src="/images/books/2021_books.png" /&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="workshops"&gt;Workshops&lt;a class="zola-anchor" href="#workshops"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First and only workshop I conducted since the start of pandemic in 2020. And this was possible only because it was online. The topic was Python scripting introduction for Biotech students. Publishing &amp;quot;100 Page Python Intro&amp;quot; was timely for this workshop.&lt;/p&gt;
&lt;p&gt;This took up most of my time during March/April along with updating existing books.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="blog-posts"&gt;Blog posts&lt;a class="zola-anchor" href="#blog-posts"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I've been consistently writing books for the past three years, but I find it difficult to come up with ideas for my programming blog. This is partly due to not wanting to repeat content from my books. Here's my favorite posts I wrote this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/my-book-writing-experience/"&gt;Paying my bills with 'free' ebooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/gnu-bre-ere-cheatsheet/"&gt;GNU BRE/ERE cheatsheet and differences between grep, sed and awk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/escaping-madness-awk-literal-field-separator/"&gt;Escaping madness to get literal field separators in awk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.perl.com/article/perl-one-liners-part-1/"&gt;Perl / Unix One-liner Cage Match, Part 1&lt;/a&gt; and &lt;a href="https://www.perl.com/article/perl-one-liners-part-2/"&gt;Perl / Unix One-liner Cage Match, Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I tried to be more consistent by posting short articles (see &lt;a href="https://learnbyexample.github.io/mini/"&gt;mini posts list&lt;/a&gt;), but lost interest. Starting a newsletter in November helped change my perspective about re-using content from my books. I've started posting tips and coding challenges that are short and easy to digest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/tips/"&gt;Programming tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/numeric-palindrome/"&gt;Numeric Palindrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/counting-nested-braces/"&gt;Counting nested braces&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was more consistent for my &lt;a href="https://learnbyexample.github.io/escapist-reviews/"&gt;Escapist Reviews&lt;/a&gt; blog that I started late last year to review novels I read.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="book-sales"&gt;Book sales&lt;a class="zola-anchor" href="#book-sales"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Had better sales compared to last year, which I really wasn't expecting. Especially when the average monthly sales was around $100 between May to September (my monthly expenses is around $150). This coincided with some health issues and the struggle to finish writing the &amp;quot;Practice Python Projects&amp;quot; book.&lt;/p&gt;
&lt;p&gt;This led me to reading articles about better landing pages, building audience on social media, affiliates, etc. I still have a long way to go, but I feel these active efforts led to much improved sales in the last quarter of the year. I ended up deciding not to use affiliates though.&lt;/p&gt;
&lt;p&gt;Here's my sales chart from Gumroad for this year (I had similar revenue from Leanpub):&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Gumroad sales in 2021" src="/images/books/gumroad_sales_2021.png" /&gt;&lt;/p&gt;
&lt;p&gt;There were plenty of reasons that led to the awesome last quarter sales. Here's some significant events I remember:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Joined hands with fellow Python authors for &lt;a href="https://learnbyexample.github.io/indie-python-extravaganza/"&gt;The Indie Python Extravaganza&lt;/a&gt; bundle (given away freely for a month)
&lt;ul&gt;
&lt;li&gt;A Twitter discussion led to the giveaway idea, which resulted in creating this bundle&lt;/li&gt;
&lt;li&gt;Combined marketing efforts by all four of us gave significant paid sales too&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Published &amp;quot;Command line text processing with GNU Coreutils&amp;quot;
&lt;ul&gt;
&lt;li&gt;In addition to my usual practice of making a new book free, this time I offered &lt;a href="https://learnbyexample.gumroad.com/l/all-books"&gt;All books bundle&lt;/a&gt; for $5 and a lot of users bought it&lt;/li&gt;
&lt;li&gt;Announcing the book on Reddit and Hacker News was well received&lt;/li&gt;
&lt;li&gt;I was beginning to improve my Twitter audience around that time, which helped a bit&lt;/li&gt;
&lt;li&gt;Got featured in Leanpub's monthly sales newsletter&lt;/li&gt;
&lt;li&gt;Jesse Smith on &lt;a href="https://distrowatch.com/weekly.php?issue=20211206#book"&gt;distrowatch.com&lt;/a&gt; wrote a lovely book review, which resulted in significant sales in December&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Getting featured on &lt;a href="https://rubyweekly.com/issues/574"&gt;Ruby weekly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/programming-deals/"&gt;Programming deals&lt;/a&gt; for the last week of November
&lt;ul&gt;
&lt;li&gt;Helped a lot by commenting on Hacker News and getting featured in blog posts of fellow Python authors&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/python-25-days-of-regex/"&gt;Interactive GUI app for Python regex&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;As part of 50 days of break from book writing, I worked on this Python app&lt;/li&gt;
&lt;li&gt;Made it to the front page of Hacker News yet again&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;quot;The Indie Python Extravaganza&amp;quot; bundle and some of my other books were featured in Leanpub's Boxing day sales&lt;/li&gt;
&lt;li&gt;And I believe creating &lt;a href="https://github.com/learnbyexample"&gt;GitHub Readme&lt;/a&gt; helped as well&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The biggest takeaway for me was to actively look for opportunities (small or big) instead of just relying on &lt;em&gt;free&lt;/em&gt; offering during book launch (which is about once in four months).&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="newsletter"&gt;Newsletter&lt;a class="zola-anchor" href="#newsletter"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During the 50 days break, the other significant project I started was &lt;a href="https://learnbyexample.gumroad.com/l/learnbyexample-weekly"&gt;learnbyexample weekly&lt;/a&gt; newsletter. This is still in early stages to point out any impact it will have on my book sales, but it certainly has been a pleasure so far to email an issue every Friday.&lt;/p&gt;
&lt;p&gt;And as mentioned earlier, this led me to write programming blog posts consistently (tips and coding challenges).&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="building-twitter-audience"&gt;Building Twitter audience&lt;a class="zola-anchor" href="#building-twitter-audience"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I joined Twitter in 2015. My follower count was less than 400 in July. In December, I crossed 1100. This is far from being impressive (I know a few authors who added more than 15000 followers during that time period).&lt;/p&gt;
&lt;p&gt;Being active on Twitter led me to awesome opportunities mentioned earlier in the Book sales section. The best tips I can give is to tweet consistently, interact with your readers and don't be afraid to participate in conversations initiated by top users. Oh, and reading articles/books about social media audience building would help too.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/learn_byexample"&gt;Follow me on Twitter&lt;/a&gt; for interesting tech nuggets 😉&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="fictional-reading"&gt;Fictional reading&lt;a class="zola-anchor" href="#fictional-reading"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I enjoy reading fantasy and science-fiction novels. I read 80+ SFF books this year and recently wrote a post listing &lt;a href="https://learnbyexample.github.io/escapist-reviews/lists/2021-favorite-sff-novels/"&gt;my top 10 favorites&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also got a chance to beta read &lt;a href="https://www.goodreads.com/book/show/57289544-the-siege-of-skyhold"&gt;The Siege of Skyhold&lt;/a&gt; and an ARC of &lt;a href="https://www.goodreads.com/book/show/58656291-bastion"&gt;Bastion&lt;/a&gt;. I find these a good way to give back to the writing community, having myself received plenty of support from strangers.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="goals-for-2022"&gt;Goals for 2022&lt;a class="zola-anchor" href="#goals-for-2022"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Foremost goal is to continue taking care of physical/mental health. And I'd be more than happy if I manage yet another year with $250+ average monthly income.&lt;/p&gt;
&lt;p&gt;Books:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I'm currently working on &lt;a href="https://learnbyexample.github.io/vim_reference/"&gt;Vim Reference Guide&lt;/a&gt; ebook. Likely to publish in the first quarter&lt;/li&gt;
&lt;li&gt;I started working on &lt;a href="https://learnbyexample.github.io/cli_text_processing_rust/"&gt;Command line text processing with Rust tools&lt;/a&gt; ebook even before &amp;quot;Command line text processing with GNU Coreutils&amp;quot;, hope to publish in 2022&lt;/li&gt;
&lt;li&gt;Have several more book topics in mind, but not sure if I'll start working on any of them. And it is possible that I'll come up with something else I fancy and work on it instead of already planned topics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interactive apps for exercises from other books, similar to the one I did for Python regex&lt;/li&gt;
&lt;li&gt;Games for fun&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Miscellaneous:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Continue to build an audience via Twitter, Newsletter, etc&lt;/li&gt;
&lt;li&gt;Contribute to other open source projects&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;Here's wishing you a very happy, healthy and prosperous 2022 👍 😇&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 21 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/wild-ride-2021/</guid></item><item><title>Finding similar API functions between Pytorch and Tensorflow with Doc2Vec</title><link>https://bytepawn.com/finding-similar-api-functions-between-pytorch-and-tensorflow-with-doc2vec.html</link><description>&lt;p&gt;I use Doc2Vec to try to find pairs of similar API functions between Pytorch and Tensorflow.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Tensorflow Pytorch" src="/images/tf_pt.png" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Wed, 21 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/finding-similar-api-functions-between-pytorch-and-tensorflow-with-doc2vec.html</guid></item><item><title>Vim tip 19: working with buffers</title><link>https://learnbyexample.github.io/tips/vim-tip-19/</link><description>&lt;p&gt;Multiple files can be opened in Vim within the same tab page and/or in different tabs. From &lt;a href="https://vimhelp.org/windows.txt.html#windows-intro"&gt;:h windows-intro&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;A buffer is the in-memory text of a file.&lt;/li&gt;
&lt;li&gt;A window is a viewport on a buffer.&lt;/li&gt;
&lt;li&gt;A tab page is a collection of windows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:e&lt;/kbd&gt; refreshes the current buffer (&lt;code&gt;:e&lt;/code&gt; is short for &lt;code&gt;:edit&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:e filename&lt;/kbd&gt; open a particular file by its path, in the same window&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:e #&lt;/kbd&gt; switch back to the previous buffer, won't work if that buffer is not named&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;6&lt;/kbd&gt; switch back to the previous buffer, works even if that buffer is not named
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;^&lt;/kbd&gt; can also be used&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:e #1&lt;/kbd&gt; open the first buffer, and so on&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:buffers&lt;/kbd&gt; show all buffers
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:ls&lt;/kbd&gt; or &lt;kbd&gt;:files&lt;/kbd&gt; can also be used&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:bn&lt;/kbd&gt; open the next file in the buffer list (&lt;code&gt;:bn&lt;/code&gt; is short for &lt;code&gt;:bnext&lt;/code&gt;)
&lt;ul&gt;
&lt;li&gt;opens the first buffer if you are on the last buffer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:bp&lt;/kbd&gt; open the previous file in the buffer list (&lt;code&gt;:bp&lt;/code&gt; is short for &lt;code&gt;:bprevious&lt;/code&gt;)
&lt;ul&gt;
&lt;li&gt;opens the last buffer if you are on the first buffer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Use &lt;kbd&gt;:set hidden&lt;/kbd&gt; if you want to switch to another buffer even if there are unsaved changes in the current buffer. Instead of this setting, you can also use &lt;kbd&gt;:hide edit filename&lt;/kbd&gt; to hide the current unsaved buffer. You'll still get an error if you try to quit Vim without saving such buffers, unless you use the &lt;code&gt;!&lt;/code&gt; modifier.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/options.txt.html#%27autowrite%27"&gt;:h 'autowrite'&lt;/a&gt; option if you want to automatically save changes when moving to another buffer.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/usr_22.txt.html#22.4"&gt;:h 22.4&lt;/a&gt; and &lt;a href="https://vimhelp.org/windows.txt.html#buffer-hidden"&gt;:h buffer-hidden&lt;/a&gt; for user and reference manuals on working with buffer list.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 20 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-19/</guid></item><item><title>Writing as a Programmer</title><link>https://cmdev.com/blog/writing-as-a-programmer/</link><description>For programmers, writing is an essential skill to build shared understanding.</description><author>The Cranky Developer on Crater Moon Development</author><pubDate>Sun, 18 Dec 2022 23:12:59 GMT</pubDate><guid isPermaLink="true">https://cmdev.com/blog/writing-as-a-programmer/</guid></item><item><title>Testing GPT-3 spatial reasoning and comprehension</title><link>https://bytepawn.com/testing-gpt-3-spatial-reasoning-and-comprehension.html</link><description>&lt;p&gt;I run experiments to determine whether, or to what degree, GPT-3 has developed an comprehension of spatial relationships.&lt;br /&gt;&lt;br /&gt; &lt;img alt="GPT-3" src="/images/square-room.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 17 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/testing-gpt-3-spatial-reasoning-and-comprehension.html</guid></item><item><title>Markdown Tables on the Fedivee</title><link>https://rjp.is/blogging/posts/2022/12/fedi-tables/</link><description>In which we see who supports Markdown tables correctly.</description><author>infrequent oscillations</author><pubDate>Fri, 16 Dec 2022 12:38:46 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2022/12/fedi-tables/</guid></item><item><title>Make the world small again</title><link>https://benovermyer.com/blog/2022/12/make-the-world-small-again/</link><description>&lt;p&gt;The world has gotten too big.&lt;/p&gt;
&lt;p&gt;A lot of online services that we've come to rely on are too intent on serving everyone. In the process, they serve no one well. Similarly, governments are trying very hard to generalize and set universal rules and policies that ultimately cause more problems than they solve. I won't talk about that latter issue in this post, though, as that would make this far longer than it needs to be. So, online services.&lt;/p&gt;
&lt;h2 id="media-services"&gt;Media Services&lt;/h2&gt;
&lt;p&gt;Streaming services like Spotify, Netflix, and so on have increasingly retired media that I'd really like to continue to have available. The reasons are varied, but usually boil down to licensing changes. For the past decade or so, I've put up with this because I usually only watch a given movie or show once every decade or so. Music streaming services like Spotify and Apple Music offer a huge wealth of music, but... even with all of that available, I tend to stick to particular genres or artists. Also, I have some eclectic tastes in music, and some of these songs have never been available on streaming services, or have been retired after licensing changes.&lt;/p&gt;
&lt;p&gt;Yesterday, I saw a post on Mastodon that stuck with me. Here it is, reproduced in text form because I hate screenshots of text:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Kids this is a reminder to collect physical copies of your favorite media. Corporations will axe your favorite show/movie/book in front of its family and make it a felony to retrieve it. Have a library.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The author is &lt;a href="https://mstdn.social/@lolennui" rel="external"&gt;@lolennui@mstdn.social&lt;/a&gt;. It was posted on Dec 14, 2022 at 02:45. Here's &lt;a href="https://mstdn.social/@lolennui/109510912705871943" rel="external"&gt;a link to the post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I think I've hit a tipping point where I agree fully with this sentiment. If you don't own something, it can disappear at any time, for any reason, and there's nothing you can do about it. A lot of these streaming services are starting to optimize for "waves" of content, and licensing titles for shorter periods of time.&lt;/p&gt;
&lt;p&gt;I still want to digitally access all of this content. I don't really want to have a massive physical library, as that can take up a huge amount of space. My parents had a collection of over 400 VHS tapes and hundreds of books twenty years ago. They filled rooms with that. So that leaves me with building and operating my own private streaming service.&lt;/p&gt;
&lt;p&gt;Which... is easier than you might think. I've set up a &lt;a href="https://jellyfin.org/" rel="external"&gt;Jellyfin&lt;/a&gt; server and begun loading media that I already own into it. This works &lt;em&gt;really well&lt;/em&gt; so far.&lt;/p&gt;
&lt;p&gt;Now comes the long haul part, though - I need to build that library. I want to legitimately own all the media I load into that server, too, so piracy is right out. Movies and TV shows are going to have to come through DVDs and Blurays that I buy and rip from. Music, though, can come from all sorts of places, since I can buy MP3s directly. I'm particularly enjoying discovering new artists I like on &lt;a href="https://bandcamp.com/" rel="external"&gt;Bandcamp&lt;/a&gt; and buying their albums.&lt;/p&gt;
&lt;h2 id="search-engines-and-discovery"&gt;Search Engines and Discovery&lt;/h2&gt;
&lt;p&gt;The mainstream search engines - Google, Bing, even DuckDuckGo - are getting worse and worse at finding meaningful and useful content. Twenty years of search engine optimization, clickbait, and design for algorithms has created a morass of content that increasingly looks designed for machines, not humans. The search engines encourage this, exacerbating the problem. When I search for something, the results are often recently "updated," very similar to a dozen other pages, and optimized to death. Trying to find a web page from the early 2000s that you know for a fact is still online? Good luck. The mainstream search engines probably don't even have it indexed anymore. They don't have infinite storage, and in order to limit their expenses, they cull the least popular (read: least algorithm-optimized) links from their indexes.&lt;/p&gt;
&lt;p&gt;It's not all bad news. More and more people are beginning to realize this problem exists. New, independent search engines that index specific niches are popping up. They're small, but serve specific needs very well. One such search engine is &lt;a href="https://wiby.me/" rel="external"&gt;Wiby&lt;/a&gt;, which specifically targets plain pages with no commercial content. It's really good for finding blog articles on topics that interest you. Another is &lt;a href="http://www.oldavista.com/" rel="external"&gt;Old'aVista&lt;/a&gt;, which indexes &lt;em&gt;old&lt;/em&gt; personal websites.&lt;/p&gt;
&lt;p&gt;Another thing that's starting to make a comeback is the web directory. Back in the late 90s and early 00s, web directories were the best way to find curated content that was directly relevant to your interests. They mostly disappeared once search engines hit their stride. Now that the web is too big for any one search engine to handle, though, web directories have an important use again.&lt;/p&gt;
&lt;p&gt;I run one such web directory. It's called &lt;a href="https://rpggen.dev" rel="external"&gt;RPGGen&lt;/a&gt;, and it's meant for discovering websites that provide content generators for tabletop role-playing games. There are many others out there. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://href.cool/" rel="external"&gt;href.cool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://indieseek.xyz/" rel="external"&gt;Indieseek&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.faunatopsites.com/" rel="external"&gt;Fauna Top Sites&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Incidentally, I discovered all three of these through Wiby.&lt;/p&gt;
&lt;h2 id="social-media"&gt;Social Media&lt;/h2&gt;
&lt;p&gt;Oh, social media. You were once so full of promise. Now, though, all social media is good for is sound bites, short videos of people or animals doing stupid things, and text that triggers various parts of our lizard brains.&lt;/p&gt;
&lt;p&gt;The original promise of social media - keeping in touch with people you care about - is all but forgotten.&lt;/p&gt;
&lt;p&gt;As it turns out, though, we never really lost the tools we need to keep in touch. I've started using email and even physical mail again to reach out to people. If I have exciting news I want to share with people I care about, I do so directly with each person. It's not much more effort than posting on social media, and it's much more rewarding.&lt;/p&gt;
&lt;p&gt;I still use social media, but I'm not nearly as active on it as most people are. I have an account on the major social media sites, but I &lt;em&gt;never&lt;/em&gt; use those anymore. The accounts are just placeholders, really. I have one friend who insists on using Facebook Messenger still, and that's honestly probably the only reason I still have a Facebook account. Twitter... well, I didn't really use it anymore to begin with, but once Melon Tusk bought it, that killed the whole thing for me. Unfortunately I still have to use Twitter to log in to two services that require social media login. I should probably fix that.&lt;/p&gt;
&lt;p&gt;The other use of social media is broadcasting our presence and thoughts to the world in general. There's a better alternative for that too: the personal website. If you don't have the technical skills to maintain a static site like the one I have here, there are options for you - &lt;a href="https://neocities.org" rel="external"&gt;Neocities&lt;/a&gt; is one such.&lt;/p&gt;
&lt;h2 id="summary-solutions-for-each"&gt;Summary: Solutions for Each&lt;/h2&gt;
&lt;p&gt;So to recap, here are my solutions for each of the above three categories of problems.&lt;/p&gt;
&lt;p&gt;To replace streaming services, &lt;strong&gt;build your own library&lt;/strong&gt;. Use Jellyfin for media. Consider leaning into a physical library, if you have the space for it.&lt;/p&gt;
&lt;p&gt;To replace mainstream search engines, use &lt;strong&gt;independent search engines&lt;/strong&gt; and &lt;strong&gt;web directories&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To replace social media, use &lt;strong&gt;email&lt;/strong&gt;, &lt;strong&gt;letters&lt;/strong&gt;, and &lt;strong&gt;phone calls&lt;/strong&gt;. Make a &lt;strong&gt;personal website&lt;/strong&gt; for your web presence.&lt;/p&gt;
&lt;p&gt;Let's make the world smaller again. Just for us.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Thu, 15 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/12/make-the-world-small-again/</guid></item><item><title>Fred Brooks' The Mythical Man-Month</title><link>https://bytepawn.com/fred-brooks-the-mythical-man-month.html</link><description>&lt;p&gt;I reflect on the core points of Fred Brooks' seminal book, The Mythical Man-Month, that I often recall and apply in my daily work.&lt;br /&gt;&lt;br /&gt; &lt;img alt="The Mythical Man-Month" src="/images/brooks.jpg" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Thu, 15 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/fred-brooks-the-mythical-man-month.html</guid></item><item><title>Reintroducing Opel: Put All Your Pelican Posts in One Org File</title><link>https://blog.nawaz.org/posts/2022/Dec/reintroducing-opel-put-all-your-pelican-posts-in-one-org-file/</link><description>&lt;p&gt;A few years ago I
&lt;a class="reference external" href="https://blog.nawaz.org/posts/2019/Dec/put-all-your-pelican-posts-in-one-org-file/"&gt;introduced&lt;/a&gt;
opel - an Emacs package that allows one to write all their
&lt;a class="reference external" href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt; posts in one Org file. It was
inspired by &lt;a class="reference external" href="https://ox-hugo.scripter.co/"&gt;ox-hugo&lt;/a&gt;. I&amp;#8217;ve since made
significant&amp;nbsp;updates.&lt;/p&gt;
&lt;div class="section" id="motivation"&gt;
&lt;h2&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Why would one want this as opposed to writing one post per&amp;nbsp;file?&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;You can …&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</description><author>Beetle Space</author><pubDate>Wed, 14 Dec 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.nawaz.org/posts/2022/Dec/reintroducing-opel-put-all-your-pelican-posts-in-one-org-file/</guid></item><item><title>CLI tip 20: expand and unexpand</title><link>https://learnbyexample.github.io/tips/cli-tip-20/</link><description>&lt;p&gt;These two commands will help you convert tabs to spaces and vice versa. Both these commands support options to customize the width of tab stops and which occurrences should be converted.&lt;/p&gt;
&lt;p&gt;The default expansion aligns at multiples of &lt;code&gt;8&lt;/code&gt; columns (calculated in terms of bytes).&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# 'apple' = 5 bytes, \t converts to 3 spaces
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# 'banana' = 6 bytes, \t converts to 2 spaces
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# 'a' and 'b' = 1 byte, \t converts to 7 spaces
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'apple\tbanana\tcherry\na\tb\tc\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; expand
&lt;/span&gt;&lt;span&gt;apple   banana  cherry
&lt;/span&gt;&lt;span&gt;a       b       c
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# 'αλε' = 6 bytes, \t converts to 2 spaces
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'αλε\tπού\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; expand
&lt;/span&gt;&lt;span&gt;αλε  πού
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, the &lt;code&gt;unexpand&lt;/code&gt; command converts initial blank (space or tab) characters to tabs. The first occurrence of a non-blank character will stop the conversion. By default, every &lt;code&gt;8&lt;/code&gt; columns worth of blanks is converted to a tab.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# input is 8 spaces followed by 'a' and then more characters
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# the initial 8 spaces is converted to a tab character
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# 'a' stops any further conversion, since it is a non-blank character
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'        a       b       c\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; unexpand &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; cat &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;T
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;^&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Ia&lt;/span&gt;&lt;span&gt;       b       c
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# input is 9 spaces followed by 'a' and then more characters
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# the initial 8 spaces is converted to a tab character
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# remaining space is left as is
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'         a       b       c\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; unexpand &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; cat &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;T
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;^&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;I&lt;/span&gt;&lt;span&gt; a       b       c
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://learnbyexample.github.io/cli_text_processing_coreutils/expand-unexpand.html"&gt;expand and unexpand&lt;/a&gt; chapter my &lt;a href="https://github.com/learnbyexample/cli_text_processing_coreutils"&gt;Command line text processing with GNU Coreutils&lt;/a&gt; ebook for more examples, options, etc.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 14 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-20/</guid></item><item><title>How good an astrophysicist is GPT-3?</title><link>https://bytepawn.com/how-good-an-astrophysicist-is-gpt-3.html</link><description>&lt;p&gt;Here I will show a "conversation" with GPT-3 to gauge how good an astrophysicist — or an illusion of an astrophysicist — it is. I will focus on cosmology questions, because that's most interesting part of the field.&lt;br /&gt;&lt;br /&gt; &lt;img alt="GPT-3" src="/images/robot-astro.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Mon, 12 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/how-good-an-astrophysicist-is-gpt-3.html</guid></item><item><title>Similar posts recommendation with Doc2Vec - Part III</title><link>https://bytepawn.com/similar-posts-recommendation-with-doc2vec-part-iii.html</link><description>&lt;p&gt;In the previous posts, I used the Doc2Vec neural network architecture to compute the similarities between my blog posts, and explored the quality of the scores. In this final post, I show how I added the final Articles You May Like recommendation sections to the blog — it's live! &lt;br /&gt;&lt;br /&gt; &lt;img alt="." src="/images/ayml.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 10 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/similar-posts-recommendation-with-doc2vec-part-iii.html</guid></item><item><title>Building TUIs with textual: first impressions</title><link>https://learnbyexample.github.io/textual-first-impressions/</link><description>&lt;p&gt;Last week, I finally started exploring &lt;a href="https://textual.textualize.io/"&gt;textual&lt;/a&gt;. The main motivation was to start implementing a few project ideas I've had in my todo list for years. I don't particularly have a preference between TUI (terminal user interface) and GUI (graphical user interface) for these projects. Seeing a few Textual demos on twitter (courtesy &lt;a href="https://twitter.com/willmcgugan"&gt;Will McGugan&lt;/a&gt;) over the past few months, I felt like exploring this framework first.&lt;/p&gt;
&lt;p&gt;For my first app, I picked a 4x4 board game — like Tic Tac Toe but form a square instead of a line. I came up with this variation in high school and been fond of coding it since college days.&lt;/p&gt;
&lt;span id="continue-reading"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h2 id="installation-and-tutorials"&gt;Installation and Tutorials&lt;a class="zola-anchor" href="#installation-and-tutorials"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://textual.textualize.io/getting_started/"&gt;Getting started&lt;/a&gt; page of the documentation will give you all the relevant installation instructions. I used &lt;code&gt;pip install 'textual[dev]'&lt;/code&gt; since the development mode has nice features like &lt;em&gt;live editing&lt;/em&gt;. As I looked up the &lt;a href="https://textual.textualize.io/guide/devtools/"&gt;Devtools&lt;/a&gt; page to link here in this blog post, I found that there's a &lt;code&gt;console&lt;/code&gt; command for &lt;code&gt;print()&lt;/code&gt; based debugging! That would've been handy while I was working on the game — sigh, I should've been more proactive in exploring the documentation site.&lt;/p&gt;
&lt;p&gt;In the &lt;em&gt;Getting started&lt;/em&gt; page, you'll also be informed about &lt;code&gt;python -m textual&lt;/code&gt; (builtin demo) and &lt;a href="https://github.com/Textualize/textual/tree/main/examples"&gt;other examples&lt;/a&gt; in the GitHub repo.&lt;/p&gt;
&lt;p&gt;After playing with the demo a bit, I went through the &lt;a href="https://textual.textualize.io/tutorial/"&gt;tutorial&lt;/a&gt; — shows how to build a Stopwatch app step-by-step.&lt;/p&gt;
&lt;p&gt;The documentation also includes &lt;a href="https://textual.textualize.io/guide/"&gt;Guide&lt;/a&gt;, &lt;a href="https://textual.textualize.io/reference/"&gt;Reference&lt;/a&gt;, &lt;a href="https://textual.textualize.io/api/"&gt;API&lt;/a&gt;, etc. I gave them a cursory glance and decided to start building my game.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; I should note that while I got introduced to programming in school about 20 years ago, I don't have much experience with projects that need more than a few hundred lines. I'm good with command-line tools and text processing with scripting languages like Python. I had a horrible experience writing an Android app a few years back, mainly due to object-oriented programming and the complexity of the project. I've improved a bit since then, but still feel like a newbie when it comes to working with classes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
&lt;h2 id="building-square-tic-tac-toe-board-game"&gt;Building Square Tic Tac Toe board game&lt;a class="zola-anchor" href="#building-square-tic-tac-toe-board-game"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Similar to the step-by-step Textual tutorial, I built the game by adding features incrementally. I &lt;a href="https://twitter.com/learn_byexample/status/1590357173519155200"&gt;tweeted my progress&lt;/a&gt; along with screenshots and recordings. Here's a summary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Managed to place 16 buttons in a grid layout&lt;/li&gt;
&lt;li&gt;Buttons now respond to clicking! And in response, the computer plays a random move&lt;/li&gt;
&lt;li&gt;Recording below shows 3 games: User wins, AI wins, Tie&lt;/li&gt;
&lt;li&gt;Added Easy/Hard modes — it is impossible to beat the AI in hard mode&lt;/li&gt;
&lt;li&gt;Almost done! Layout is better now and starting new game is now a button instead of a shortcut keybinding&lt;/li&gt;
&lt;li&gt;Cleaned up code a bit and posted on GitHub&lt;/li&gt;
&lt;li&gt;Next step: write a blog post (this post!)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Visit &lt;a href="https://github.com/learnbyexample/TUI-apps/tree/main/SquareTicTacToe"&gt;my GitHub repo&lt;/a&gt; for the code, game rules and other details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had made a &lt;a href="https://learnbyexample.github.io/practice_python_projects/square_tic_tac_toe/square_tic_tac_toe.html"&gt;GUI version of this game using tkinter&lt;/a&gt; last year. I copied most of the game logic from there, so I didn't much struggle with object-oriented programming in this case. Here's a sample screenshot from the finished code:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Sample screenshot for Square Tic Tac Toe game" src="/images/textual/square_tictactoe.png" /&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="what-i-liked"&gt;What I liked&lt;a class="zola-anchor" href="#what-i-liked"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned before, Textual supports &lt;em&gt;live editing&lt;/em&gt; mode. The command is &lt;code&gt;textual run --dev script.py&lt;/code&gt; and this helps you experiment with CSS. I found this very helpful while trying out layout combinations, margin, padding, etc.&lt;/p&gt;
&lt;p&gt;The default colors were great too. I didn't have to think about choosing colors (except for setting background color for header and game status). The framework even provides an easy way to allow users to switch between dark and light themes! Though, I haven't yet figured out how to set light theme as the default (I worked around by explicitly adding a call to the theme toggle method).&lt;/p&gt;
&lt;p&gt;Overall, the code was significantly shorter compared to the &lt;code&gt;tkinter&lt;/code&gt; version I did last year. That version had a few more features, but I'd say Textual felt much easier to reason about. I remember having to spend days shifting through stackoverflow threads and &lt;a href="https://tkdocs.com/index.html"&gt;tkdocs&lt;/a&gt; to get the GUI version working.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="what-gave-me-trouble"&gt;What gave me trouble&lt;a class="zola-anchor" href="#what-gave-me-trouble"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Struggling with layout isn't new for me. I started with 4x4 grid for the board, which was fairly straightforward. Problems arose when I wanted to add status text area to the left and control buttons to the right. Placing them left/right was easy to do with &lt;em&gt;dock&lt;/em&gt; in CSS. But, I couldn't get them to align well — too much spacing around the 4x4 board. I was trying to give 50% to 60% for the board and the remaining evenly divided for the other two elements. After some experimentation, what worked was giving 20% to status, 25% to control and &lt;em&gt;not&lt;/em&gt; assigning a width value for the board.&lt;/p&gt;
&lt;p&gt;I initially used a button for the status because I couldn't find a &lt;em&gt;textbox&lt;/em&gt; widget (edit: Textual now has a &lt;code&gt;Label&lt;/code&gt; widget). I knew that &lt;a href="https://textual.textualize.io/widgets/static/"&gt;Static&lt;/a&gt; widget can display text, but I didn't find how to dynamically change the text from that documentation page. I thought I'll have to make a custom widget, but when I went to &lt;a href="https://textual.textualize.io/guide/widgets/"&gt;Widgets guide&lt;/a&gt;, I found that &lt;code&gt;Static&lt;/code&gt; already has an &lt;code&gt;update()&lt;/code&gt; method!&lt;/p&gt;
&lt;p&gt;I probably missed something (or perhaps part of the roadmap), but I found it strange to have a single &lt;code&gt;on_button_pressed()&lt;/code&gt; method to handle on click event for every &lt;code&gt;Button&lt;/code&gt; widget. I'd prefer a way to bind a method to the buttons, like &lt;code&gt;tkinter&lt;/code&gt; provides.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="next-steps"&gt;Next steps&lt;a class="zola-anchor" href="#next-steps"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned before, I have several projects in my todo list. The next one I want to try is an app for interactive exercises for &lt;a href="https://learnbyexample.github.io/books/"&gt;my ebooks&lt;/a&gt;. Last year, I made one for &lt;a href="https://github.com/learnbyexample/py_regular_expressions/tree/master/interactive_exercises"&gt;Python regular expressions&lt;/a&gt; using &lt;code&gt;tkinter&lt;/code&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 09 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/textual-first-impressions/</guid></item><item><title>Strong Opinions &amp;amp; Eroding Discourse</title><link>https://blog.bayindirh.io/blog/strong-opinions-eroding-discourse/</link><description>&lt;p&gt;I have been observing a trend both in blogs and general internet discourse, but instead of pointing fingers, I decided to sit back, observe and assume that I'm the man who was yelling at the cloud. However, an &lt;a href="https://yurichev.org/clang/"&gt;article&lt;/a&gt;, and &lt;a href="https://news.ycombinator.com/item?id=33768449"&gt;comments on the orange site&lt;/a&gt; convinced me that I'm not the only one with this observation, hence I decided to note it here.&lt;/p&gt;
&lt;p&gt;We're arguably going through the second big shift in computing history with a renewed interest in programming due to exponential rise of computing in our daily lives in visible and invisible ways. Sustaining this growth requires a much bigger brain power, and not falling behind in this global technology race. In turn, this fuels discourse and information sharing, and in turn, an evolved version of the flame wars of the 80s and 90s is taking place.&lt;/p&gt;
&lt;p&gt;The reason for this is simple, in my opinion. We’re building more sophisticated and ambitious things, which results in bigger and more sensational outcomes. People involved in and excited by these technologies hype it knowingly or unknowingly, and when someone opposes their views, they get upset and answer back forcefully. These sparks ignite the already flammable atmosphere, and flames ensue.&lt;/p&gt;
&lt;p&gt;While flame wars look like a natural outcome, its existence is detrimental to neutral and healthy discourse on the bigger scale. Eliminating this phenomenon is impossible in my opinion but, minimizing its occurrence is highly beneficial.&lt;/p&gt;
&lt;p&gt;The key to reducing flame wars is a simple but hard to master technique: “listen (read) intently and talk (write) clearly and calmly”. Applying this requires a level head and is not always possible, I know. Also, some people are very good at intentionally triggering the emotions of the other party. However, going above and beyond this simple shouting matches is beneficial for both arguing and spectating parties, because it maximizes the chances for learning something, and leaving the discussion in a better place.&lt;/p&gt;
&lt;p&gt;Next time, please try to reread the words of the person who’s answering you slowly and intently if you find yourself angrier than you should be, and answer ten minutes later if you can help it.&lt;/p&gt;
&lt;p&gt;You’ll be amazed how this one weird trick can change your conversations for the better.&lt;/p&gt;
&lt;p&gt;Until next time,&lt;/p&gt;
&lt;p&gt;Be kind.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Fri, 09 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/strong-opinions-eroding-discourse/</guid></item><item><title>Rendering LaTeX Formulae in mastodon.el</title><link>https://blog.nawaz.org/posts/2022/Dec/rendering-latex-formulae-in-mastodonel/</link><description>&lt;p&gt;On &lt;a class="reference external" href="https://joinmastodon.org/"&gt;Mastodon&lt;/a&gt; I follow a number of folks
at the &lt;a class="reference external" href="https://mathstodon.xyz"&gt;Mathstodon&lt;/a&gt; instance. Because that
instance is about mathematics, they&amp;#8217;ve enabled the rendering of LaTeX
formulae in their web&amp;nbsp;interface.&lt;/p&gt;
&lt;p&gt;However, since I am &lt;em&gt;not&lt;/em&gt; on that particular instance, all the toots
with equations show up as ugly LaTeX when …&lt;/p&gt;</description><author>Beetle Space</author><pubDate>Thu, 08 Dec 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.nawaz.org/posts/2022/Dec/rendering-latex-formulae-in-mastodonel/</guid></item><item><title>Python tip 20: saving and loading json</title><link>https://learnbyexample.github.io/tips/python-tip-20/</link><description>&lt;p&gt;JSON (JavaScript Object Notation) is one of the ways you can store and retrieve data necessary for functioning of an application. For example, my projects &lt;a href="https://github.com/learnbyexample/py_regular_expressions/tree/master/interactive_exercises"&gt;Python regex exercises&lt;/a&gt; and &lt;a href="https://github.com/learnbyexample/TUI-apps/blob/main/CLI-Exercises"&gt;Linux CLI text processing exercises&lt;/a&gt; need to load questions and save user progress. You might wonder why not just a plain text file? I needed &lt;code&gt;dict&lt;/code&gt; in the code anyway and JSON offered seamless transition. Also, this arrangement avoided having to write extra code and test it for potential parsing issues.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;json&lt;/code&gt; builtin module is handy for such purposes. Here's an example of saving a &lt;code&gt;dict&lt;/code&gt; object:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; import &lt;/span&gt;&lt;span&gt;json
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;86&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;92&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rajan'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;79&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; with &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;open&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'marks.json'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'w'&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;as &lt;/span&gt;&lt;span&gt;f:
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span&gt;json.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;dump&lt;/span&gt;&lt;span&gt;(marks, f, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;indent&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, &lt;code&gt;indent&lt;/code&gt; is used for pretty printing. Here's how the file looks like:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span&gt;$ cat marks.json
&lt;/span&gt;&lt;span&gt;{
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;Rahul&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;86&lt;/span&gt;&lt;span&gt;,
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;Ravi&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;92&lt;/span&gt;&lt;span&gt;,
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;Rohit&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;,
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;Rajan&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;79
&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's an example of loading a JSON file:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; with &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;open&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'marks.json'&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;as &lt;/span&gt;&lt;span&gt;f:
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span&gt;marks &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;json.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;load&lt;/span&gt;&lt;span&gt;(f)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;86&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;92&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rajan'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;79&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://docs.python.org/3/library/json.html"&gt;docs.python: json&lt;/a&gt; for documentation, more examples, other methods, caveats and so on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 07 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-20/</guid></item><item><title>Abstraction is Expensive</title><link>https://specbranch.com/posts/expensive-abstraction/</link><description>&lt;p&gt;As you build a computer system, little things start to show up: maybe that database query is awkward
for the feature you are building, or you find your server getting bogged down transferring gigabytes
of data in hexadecimal ASCII, or your app translates itself to Japanese on the fly for hundreds of
thousands of separate users.  These are places where your abstractions are misaligned - your app
would be quantitatively better if it had a better DB schema, a way to transfer binary data, or
native internationalization for your Japanese users.  Each of these misalignments carries a cost.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Wed, 07 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/expensive-abstraction/</guid></item><item><title>First Day in Dragonflight</title><link>https://benovermyer.com/blog/2022/12/first-day-in-dragonflight/</link><description>&lt;p&gt;So after coming home from a business trip, I finally got to play the new World of Warcraft expansion yesterday. It's so much fun! The last time I remember thoroughly enjoying the initial experience of a WoW expansion was Wrath of the Lich King over ten years ago.&lt;/p&gt;
&lt;p&gt;The starting area of the Dragon Isles is absolutely gorgeous. That the expansion encourages exploration makes it even better. There are little things to discover all over the place. The new dragonriding mechanic - basically Flight 2.0 - is really enjoyable and dovetails into the exploration. The Dragon Isles are definitely designed with dragonriding in mind, because there are pillars, canyons, towers, and all other manner of interesting obstacles and terrain to fly around, through, and in.&lt;/p&gt;
&lt;p&gt;Something that caught me completely by surprise was the changes to professions. They added a level of depth that is on par with Final Fantasy XIV crafting, and may even draw some inspiration from Star Wars: Galaxies in some limited ways. Even the gathering professions got a little bit of depth added to them, though they at least are still not as complex as FFXIV or SWG. It's going to take me awhile to learn the new systems, and I adore that I have to do that. It makes crafting much less boring and much more rewarding.&lt;/p&gt;
&lt;p&gt;The story thus far is less cataclysmic than previous expansions' stories. Yes, there's a big bad, and letting them win would be very not-good. But it doesn't feel like I just got done saving the world and now I have to save it again; instead, the villain story is only part of a larger narrative around restoring the dragonflights to their former glory and their former home.&lt;/p&gt;
&lt;p&gt;All of this, in one day. I'm really looking forward to playing more.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Mon, 05 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/12/first-day-in-dragonflight/</guid></item><item><title>Similar posts recommendation with Doc2Vec - Part II</title><link>https://bytepawn.com/similar-posts-recommendation-with-doc2vec-part-ii.html</link><description>&lt;p&gt;In the previous post, I used the Doc2Vec neural network architecture to compute the similarities between my blog posts. In this second post I investigate the results further by examining clusters in graphs.&lt;br /&gt;&lt;br /&gt; &lt;img alt="." src="/images/doc2vec_graph_1.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 04 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/similar-posts-recommendation-with-doc2vec-part-ii.html</guid></item><item><title>Similar posts recommendation with Doc2Vec - Part I</title><link>https://bytepawn.com/similar-posts-recommendation-with-doc2vec.html</link><description>&lt;p&gt;One of the things I learned at Facebook is the power of recommendations. Examples are People You May Know (PYMK), Groups You May Like (GYML) and Pages You May Like (PYML). Inspired by these, I am planning to add an Articles You May Like widget to Bytepawn, based on the semantic similarity of blog posts. I use the Doc2Vec neural network architecture to compute the similarity between my blog posts, and return the top 3 recommendations for each page.&lt;br /&gt;&lt;br /&gt; &lt;img alt="." src="/images/doc2vec_similarity_matrix.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 03 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/similar-posts-recommendation-with-doc2vec.html</guid></item><item><title>2022–12–02: Pinephone kernel news and some bits about the keyboard, too</title><link>https://xnux.eu/log/#076</link><author>megi's PinePhone Development Log</author><pubDate>Fri, 02 Dec 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#076</guid></item><item><title>Is it worth writing about?</title><link>http://notes.eatonphil.com/is-it-worth-writing-about.html</link><description>&lt;p&gt;You acquire a skill or experience through time and effort,
then downplay the impact of writing and sharing the learning
process.&lt;/p&gt;
&lt;p&gt;Professionals seem naturally to imagine a high bar for what
is worth writing about.&lt;/p&gt;
&lt;p&gt;I think that's misguided. This article is not criticism of folks with
these beliefs, but rather encouragement for folks looking for a reason
to write.&lt;/p&gt;
&lt;p&gt;There are (at least) a few concrete reasons to write about what you've
learned, even when you don't think it's novel.&lt;/p&gt;
&lt;h3 id="to-practice-writing"&gt;To practice writing&lt;/h3&gt;&lt;p&gt;This is the easiest reason. While practice does not imply improvement,
you cannot improve without practice.&lt;/p&gt;
&lt;p&gt;Every time you learn something is a chance to write down both what
you've learned and also how you learned it.&lt;/p&gt;
&lt;p&gt;For professional developers this chance happens all the time. Daily,
really. But most developers, even those who want to write more, let
the opportunity slip.&lt;/p&gt;
&lt;h3 id="providing-variety"&gt;Providing variety&lt;/h3&gt;&lt;p&gt;When I learn a topic I normally go through dozens of posts, papers,
docs, videos or books to find a version that clicks. If I can. I
prefer to start with blog posts and often there are not blog posts on
the subject. Books, docs, videos, and academic papers aren't often as
accessible.&lt;/p&gt;
&lt;p&gt;Even if you're writing about a popular topic, there's still a chance
your post gets through to someone in a way other posts do not.&lt;/p&gt;
&lt;p class="note"&gt;
  For programmers there are notorious topics you can avoid if
  you'd like ("What is a monad", "Why is lisp interesting", "Kubernetes
  sucks"). Or not. I've fallen into those traps.
&lt;/p&gt;&lt;p&gt;Additionally, as you gain experience as a programmer (or product
manager, or whatever), your perspective and approach becomes both more
interesting and more valuable.&lt;/p&gt;
&lt;p&gt;I don't recall ever thinking: "I wish they'd write less". But I'm
always wishing some folks wrote more, or at all.&lt;/p&gt;
&lt;p&gt;Some folks with experience, writing about widely varied topics in
software include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://eli.thegreenplace.net/"&gt;Eli Bendersky&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nullprogram.com/blog/2015/03/19/"&gt;Chris Wellons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;And &lt;a href="https://zserge.com/"&gt;Serge Zaitsev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But experience need not be a prerequisite. Experts (who don't practice
explaining) easily forget how they came to their current
understanding. A beginner's experience is valuable for everyone who is
not a beginner, sometimes also for beginners.&lt;/p&gt;
&lt;h3 id="to-cement-understanding"&gt;To cement understanding&lt;/h3&gt;&lt;p&gt;Finally, honest writing &lt;em&gt;forces&lt;/em&gt; you to either understand the dark
corners of what you've learned or to ask for help in these dark
corners.&lt;/p&gt;
&lt;p&gt;I have repeatedly wrestled with topics in software only to be further
forced to explain &lt;em&gt;why&lt;/em&gt; (or &lt;em&gt;how&lt;/em&gt;) when I write.&lt;/p&gt;
&lt;p&gt;And it has often forced me to restructure code or ideas in ways that
are easier to explain. I think that's a pretty valuable act for the
long-term.&lt;/p&gt;
&lt;h3 id="bad-faith"&gt;Bad faith&lt;/h3&gt;&lt;p&gt;There's a bad faith argument that you sometimes see. Here's a
variation that comes to mind.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The internet is already full of crap. People who aren't experts are
  just making it worse.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I hope you ignore these comments. :) If there's a quality problem that
is genuinely causing harm, that's for search engines and trade
organizations to deal with.&lt;/p&gt;
&lt;h3 id="in-the-extreme"&gt;In the extreme&lt;/h3&gt;&lt;p&gt;&lt;a href="https://til.simonwillison.net/"&gt;Simon Willison's TIL&lt;/a&gt; site is the
most prolific version of this I've ever seen. I don't know if I
personally aspire to Simon's level, but I think it's worth seeing.&lt;/p&gt;
&lt;h3 id="topics"&gt;Topics&lt;/h3&gt;&lt;p&gt;Some topics I think are always worth writing about and sharing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your process, failures and successes, to figuring something out&lt;/li&gt;
&lt;li&gt;How to hack on some major open source project&lt;/li&gt;
&lt;li&gt;In-depth comparison of projects or approaches, down to source code, benchmarks, and architecture when relevant&lt;/li&gt;
&lt;li&gt;Building minimal versions of some production system&lt;/li&gt;
&lt;li&gt;How some major systems works under the hood, down to the code&lt;/li&gt;
&lt;li&gt;Mistakes you made in structuring organizations, or production architecture, or testing, etc.&lt;/li&gt;
&lt;li&gt;How to get the dang configuration right for testing Electron apps in Github Actions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For programming posts specifically: I strongly encourage you to
include or walk through working code. Have tests. And have the code
build process hooked up to GitHub Actions or SourceHut CI or
whatever. This helps ensure your work is still relevant over time.&lt;/p&gt;
&lt;h3 id="when-you-write"&gt;When you write&lt;/h3&gt;&lt;p&gt;Write to explain and teach. When you don't understand something, call
out that you don't understand it. That's not a bad thing, and the
internet is normally happy to help.&lt;/p&gt;
&lt;p&gt;Don't shy away from showing code, showing things that broke, showing
the ugly process. It's encouraging for others to see.&lt;/p&gt;
&lt;h3 id="end-goal"&gt;End goal&lt;/h3&gt;&lt;p&gt;Well, ideally we have fewer clickbait "5 best React alternatives"
articles and more thoughtful pieces intended to teach and educate with
a bit of rigor.&lt;/p&gt;
&lt;p&gt;It's better for individuals and for companies. It's better for the
internet.&lt;/p&gt;
&lt;h3 id="community"&gt;Community&lt;/h3&gt;&lt;p&gt;If you want a community of folks where you can find encouragement to
write and eyes to review drafts, check out the #writing-and-drafts
channel on the &lt;a href="https://eatonphil.com/discord.html"&gt;Software Internals Discord&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="is-it-worth-writing-about?"&gt;Is it worth writing about?&lt;/h3&gt;&lt;p&gt;Well if you come to me I'm almost surely going to say yes. Poor
Betteridge.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Wrote a short post as a bit of encouragement to folks who want to write more but imagine a high bar for what's worthwhile.&lt;br /&gt;&lt;br /&gt;tldr; if you ask me it's almost always going to be a yes. And I think there's a path toward a higher-quality internet.&lt;a href="https://t.co/Nn6BvXhNdZ"&gt;https://t.co/Nn6BvXhNdZ&lt;/a&gt; &lt;a href="https://t.co/KELvsxnr2w"&gt;pic.twitter.com/KELvsxnr2w&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1598441836284203011?ref_src=twsrc%5Etfw"&gt;December 1, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Thu, 01 Dec 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/is-it-worth-writing-about.html</guid></item><item><title>Ask HN: Data Scientists, what libraries do you use for timeseries forecasting?</title><link>https://bytepawn.com/ask-hn-data-scientists-what-libraries-do-you-use-for-timeseries-forecasting.html</link><description>&lt;p&gt;One of the most common Data Science tasks in a business setting is timeseries forecasting. I was curious what methods and libraries other Data Scientists use, so I posted an "Ask HN" on Hacker News. The post generated 89 comments, most of them high-quality. This is my summary of the discussion.&lt;br /&gt;&lt;br /&gt; &lt;img alt="." src="/images/ts-forecasting.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Wed, 30 Nov 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/ask-hn-data-scientists-what-libraries-do-you-use-for-timeseries-forecasting.html</guid></item><item><title>Vim tip 18: moving within long lines</title><link>https://learnbyexample.github.io/tips/vim-tip-18/</link><description>&lt;p&gt;Here are Normal mode commands you can use to move within long lines that are spread over multiple screen lines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;g0&lt;/kbd&gt; move to the beginning of the current screen line&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;g^&lt;/kbd&gt; move to the first non-blank character of the current screen line&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;g$&lt;/kbd&gt; move to the end of the current screen line&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;gj&lt;/kbd&gt; move down by one screen line, prefix a count to move down by that many screen lines&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;gk&lt;/kbd&gt; move up by one screen line, prefix a count to move up by that many screen lines&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;gm&lt;/kbd&gt; move to the middle of the current screen line
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Note&lt;/strong&gt; that this is based on the screen width, not the number of characters in the line!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;gM&lt;/kbd&gt; move to the middle of the current line
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Note&lt;/strong&gt; that this is based on the total number of characters in the line&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/motion.txt.html#left-right-motions"&gt;:h left-right-motions&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 29 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-18/</guid></item><item><title>What problem are we trying to solve?</title><link>/2022/11/28/What-problem-are-we-trying-to-solve/</link><description>&lt;p&gt;If you want to seem like the smartest person in the room, wait for a break in conversation, after sitting quiet for 15 minutes, and ask &lt;em&gt;&amp;ldquo;What problem are we trying to solve here?&amp;rdquo;&lt;/em&gt; It works every time.&lt;/p&gt;
&lt;p&gt;We’ve all been there. You walk into a meeting, there are 10 people in it. It gets rolling, different folks chiming in. A few people seem to be taking personal notes, they always do. There is the person that scheduled the meeting, but they’re not the person that usually makes decisions. It’s primarily going back and forth between 3 individuals with 7 others watching on. You’re 15 minutes in, and while there has been lively discussion already… you find yourself back on the original point from minute 1 seemingly lost 14 minutes and you’re unsure to what.&lt;/p&gt;
&lt;p&gt;A healthier environment ideally has an agenda sent out ahead of time. Based on the agenda there is a clear structure planned for the meeting which presumably points to a clear goal. Even without an agenda an alternative structure would be a clearly stated goal in the invite. Within the meeting you &lt;a href="https://www.heavybit.com/library/video/executive-communication"&gt;SCQA&lt;/a&gt;-it up live. Huge bonus points if the meeting invite includes a link to the &lt;strong&gt;notes doc&lt;/strong&gt; where meeting notes will be transcribed by an &lt;strong&gt;explicit scribe&lt;/strong&gt; for the meeting, &lt;strong&gt;sent out after&lt;/strong&gt; for folks to agree/confirm as a good record of the meeting.&lt;/p&gt;
&lt;p&gt;As a facilitator as good as you may be, you’re still going to end up in the first situation. Every time wait 10-15 minutes, then ask the question. It seems to be more effective after you’ve had the detour vs. leading off with it in the first 1 minute. Even better internalize the question to yourself vs. just making yourself look good by asking it (which will happen).&lt;/p&gt;</description><author>CRAIG KERSTIENS</author><pubDate>Mon, 28 Nov 2022 21:23:56 GMT</pubDate><guid isPermaLink="true">/2022/11/28/What-problem-are-we-trying-to-solve/</guid></item><item><title>Adding More Images to this Blog</title><link>https://blog.nawaz.org/posts/2022/Nov/adding-more-images-to-this-blog/</link><description>&lt;p&gt;I suck at art. As such, my blog has been mostly text with few&amp;nbsp;images.&lt;/p&gt;
&lt;p&gt;Recently I started playing with &lt;a class="reference external" href="https://stability.ai/blog/stable-diffusion-public-release"&gt;Stable
Diffusion&lt;/a&gt;
on my &lt;span class="caps"&gt;PC&lt;/span&gt;, and it occurred to me I can use it to generate some artwork
for the blog. As a result, I&amp;#8217;ve added images to various …&lt;/p&gt;</description><author>Beetle Space</author><pubDate>Sun, 27 Nov 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.nawaz.org/posts/2022/Nov/adding-more-images-to-this-blog/</guid></item><item><title>Fall/Winter 2022 Update… Let the 3d Printing Begin!</title><link>https://miscdotgeek.com/fall-winter-2022-update-let-the-3d-printing-begin/</link><description>&lt;p&gt;Hey everyone, I&amp;#8217;m very sorry for the long absence. It&amp;#8217;s been a while since I&amp;#8217;ve written, and so much has changed. In August, I took my 1988 Suburban, loaded it up with a 12 foot UHaul trailer, and dragged all my belongings from rural Western Washington to rural Western Nevada, about 30 miles from Reno. &amp;#8230; &lt;/p&gt;
&lt;p&gt;&lt;a class="more-link btn" href="https://miscdotgeek.com/fall-winter-2022-update-let-the-3d-printing-begin/" rel="noopener noreferrer" target="_self"&gt;Continue reading&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://miscdotgeek.com/fall-winter-2022-update-let-the-3d-printing-begin/" rel="noopener noreferrer" target="_self"&gt;Fall/Winter 2022 Update&amp;#8230; Let the 3d Printing Begin!&lt;/a&gt; appeared first on &lt;a href="https://miscdotgeek.com" rel="noopener noreferrer" target="_self"&gt;MiscDotGeek&lt;/a&gt;.&lt;/p&gt;</description><author>MiscDotGeek</author><pubDate>Fri, 25 Nov 2022 20:25:24 GMT</pubDate><guid isPermaLink="true">https://miscdotgeek.com/fall-winter-2022-update-let-the-3d-printing-begin/</guid></item><item><title>Festive deals for books on Python, Linux, JavaScript, Regular Expressions and more</title><link>https://learnbyexample.github.io/programming-deals-2022/</link><description>&lt;p&gt;Hello!&lt;/p&gt;
&lt;p&gt;Here are some exciting deals for my programming ebooks as well as from other creators.&lt;/p&gt;
&lt;span id="continue-reading"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h2 id="my-ebooks"&gt;My ebooks&lt;a class="zola-anchor" href="#my-ebooks"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Offers valid till 30-Nov-2022:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.gumroad.com/l/all-books/FestiveOffer"&gt;All 13 Books Bundle&lt;/a&gt; — $10 (normal price $28)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.gumroad.com/l/py_projects/FestiveOffer"&gt;Practice Python Projects&lt;/a&gt; — FREE (normal price $10)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.gumroad.com/l/js_regexp/FestiveOffer"&gt;JavaScript RegExp&lt;/a&gt; — FREE (normal price $10)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.gumroad.com/l/python-bundle/FestiveOffer"&gt;Learn by example Python bundle&lt;/a&gt; — $3 (normal price $15)&lt;/li&gt;
&lt;/ul&gt;
&lt;p align="center"&gt;&lt;a href="https://learnbyexample.gumroad.com/l/all-books/FestiveOffer"&gt;&lt;img alt="All books bundle" src="/images/books/all_books_bundle.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="indie-creators"&gt;Indie creators&lt;a class="zola-anchor" href="#indie-creators"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.blog.pythonlibrary.org/2022/11/22/python-black-friday-cyber-monday-sales-2022/"&gt;Python books by Michael Driscoll&lt;/a&gt; — $10 off for all books, 20% off for Teach Me Python&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pythonmorsels.com/pricing/"&gt;Python Morsels&lt;/a&gt; — save up to $108 a year on Python Morsels, until Nov 28 (skill-honing system that helps developers deepen their Python skills)
&lt;ul&gt;
&lt;li&gt;see also author's &lt;a href="https://treyhunner.com/2022/11/python-black-friday-and-cyber-monday-sales-2022/"&gt;blog post&lt;/a&gt; for comprehensive links to other Python deals&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://adamchainz.gumroad.com/l/byddx"&gt;Boost Your Django DX&lt;/a&gt; and &lt;a href="https://adamchainz.gumroad.com/l/suydt"&gt;Speed Up Your Django Tests&lt;/a&gt; — 50% off (plus further 50% off based on GDP) until Nov 28
&lt;ul&gt;
&lt;li&gt;see also author's &lt;a href="https://adamj.eu/tech/2022/11/21/django-black-friday-deals-2022/"&gt;blog post&lt;/a&gt; for comprehensive links to other Django-related deals&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/reuvenmlerner/status/1595402066213601280"&gt;Python, Git, and Pandas courses&lt;/a&gt; — 40% off&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bhavaniravi.gumroad.com/l/technical-blogging/WRITELIKEPRO"&gt;Practical Guide to Technical Blogging&lt;/a&gt; is 34% off and &lt;a href="https://bhavaniravi.gumroad.com/l/LaFSj/BLACKPYTHON"&gt;Python To Projects bootcamp&lt;/a&gt; is 20% off&lt;/li&gt;
&lt;li&gt;&lt;a href="https://shrutibalasa.gumroad.com/l/css-flex-and-grid/BlackFriday22"&gt;Complete Guide to CSS Flex and Grid&lt;/a&gt; — 60% off on all versions of the eBook (4 days starting from Nov 24)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/OzolinsJanis/status/1595743978531348480"&gt;Explain Ideas Visually&lt;/a&gt; — 50% OFF&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 id="miscellaneous"&gt;Miscellaneous&lt;a class="zola-anchor" href="#miscellaneous"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nostarch.com/blog/2022-holiday-gift-guide"&gt;NoStarch Press&lt;/a&gt; — Holiday Gift Guide, 35% off until Nov 28&lt;/li&gt;
&lt;li&gt;&lt;a href="https://media.pragprog.com/newsletters/2022-11-18.html"&gt;The Pragmatic Bookshelf&lt;/a&gt; — 40% off on all ebooks and audio books&lt;/li&gt;
&lt;li&gt;&lt;a href="https://deals.manning.com/thanksgiving/"&gt;Manning Publications&lt;/a&gt; — save 50% when you buy 2 or more eBooks, liveProjects, or liveVideos&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mailchi.mp/leanpub/monthly-sale-2022-november-black-friday"&gt;Leanpub Monthly Sale&lt;/a&gt; — offers for programming books, bundles and courses&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/giveaway/black-friday/"&gt;Real Python Giveaway&lt;/a&gt; — a chance to win one of three prizes, until Nov 25&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/0x90n/InfoSec-Black-Friday"&gt;InfoSec Hack Friday&lt;/a&gt; — InfoSec related software/tools&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opsdisk.gumroad.com/l/cphlab/blackfriday2022"&gt;The Cyber Plumber's Lab Guide and Interactive Access&lt;/a&gt; — 50% OFF&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/trungdq88/Awesome-Black-Friday-Cyber-Monday"&gt;Huge list of awesome deals&lt;/a&gt; — tools, productivity, books, courses, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;Happy learning :)&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 25 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/programming-deals-2022/</guid></item><item><title>Do You Trust Your Tax Preparer?</title><link>https://blog.nawaz.org/posts/2022/Nov/do-you-trust-your-tax-preparer/</link><description>&lt;p&gt;For most of my life, I&amp;#8217;ve done my own taxes - using paper and pen. If
you have the standard W-2 income, it&amp;#8217;s fairly&amp;nbsp;easy.&lt;/p&gt;
&lt;p&gt;Thrice, though, my tax situation got complicated enough that I paid a
tax preparer to do the&amp;nbsp;taxes.&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://blog.nawaz.org/images/taxes/cpa.jpg"&gt;
&lt;img alt="Evil tax preparer" src="https://blog.nawaz.org/images/taxes/cpa.jpg" /&gt;
&lt;/a&gt;
&lt;div class="section" id="first"&gt;
&lt;h2&gt;First&lt;/h2&gt;
&lt;p&gt;I had gotten married the …&lt;/p&gt;&lt;/div&gt;</description><author>Beetle Space</author><pubDate>Wed, 23 Nov 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.nawaz.org/posts/2022/Nov/do-you-trust-your-tax-preparer/</guid></item><item><title>Regarding social media, web presence, and dumpster fires</title><link>https://benovermyer.com/blog/2022/11/regarding-social-media/</link><description>&lt;p&gt;So, some rich sociopath bought Twitter and seems hell-bent on destroying it.&lt;/p&gt;
&lt;p&gt;I haven't used Twitter in years, except to occasionally check the status of a misbehaving SaaS. So, Twitter's implosion doesn't really bother me. It did prompt me to log back into &lt;a href="https://fosstodon.org/@dungeonHack" rel="external"&gt;my Mastodon account&lt;/a&gt; and start using it actively. So in that sense, Twitter's implosion has affected me.&lt;/p&gt;
&lt;p&gt;Tons of other people have migrated to the Fediverse as a direct result of the Twitter dumpster fire. And by tons, I mean hundreds of thousands. I've never seen Mastodon so active. It's causing no end of strain and hardship for Mastodon server administrators. However, it also is having an effect that I've wanted for years - decentralization of social networks is expanding into the mainstream.&lt;/p&gt;
&lt;p&gt;The last time I saw anything like this was when Google decided to murder Google+. G+ had been host to a huge and active tabletop role-playing game community, and when the service died, that community scrambled to find a replacement. Back then, the community seemed to divide between just blogging, using Facebook, and using MeWe. The latter two are centralized services, but the first was decentralized, and I was happy to see more people blogging.&lt;/p&gt;
&lt;p&gt;Now, with the mass adoption of Mastodon, it seems the needle is moving even futher into decentralization. At least, this is true for the TTRPG community. I love this. I've been blogging since the early 2000s... maybe since the late 90s, if you count sporadic updates to a static home page.&lt;/p&gt;
&lt;p&gt;Hopefully this is a trend and not just a one-off event.&lt;/p&gt;
&lt;p&gt;Something that still needs to be addressed, though, is the discovery side of things. Modern search engines like Google and Bing are getting worse and worse at actually finding small websites that don't care about SEO. Why &lt;em&gt;should&lt;/em&gt; personal websites care about SEO, anyway? Their focus should be on their own identity. Discovery should be a community problem, rather than an individual's. My own contribution to this is a web directory called &lt;a href="https://rpggen.dev" rel="external"&gt;RPGGen&lt;/a&gt;. Given how enormous the tabletop role-playing game web community has gotten, maybe we need a dedicated search engine that only crawls role-playing game sites. That would be an interesting project.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Wed, 23 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/11/regarding-social-media/</guid></item><item><title>CLI tip 19: extended globs</title><link>https://learnbyexample.github.io/tips/cli-tip-19/</link><description>&lt;p&gt;The Bash shell provides &lt;code&gt;extglob&lt;/code&gt; option for advanced pattern matching of filenames. These will help you apply regexp like quantifiers, provide alternate patterns and negation. From &lt;code&gt;man bash&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Extended glob&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;?(pattern-list)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Matches zero or one occurrence of the given patterns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*(pattern-list)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Matches zero or more occurrences of the given patterns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;+(pattern-list)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Matches one or more occurrences of the given patterns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@(pattern-list)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Matches one of the given patterns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;!(pattern-list)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Matches anything except one of the given patterns&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Extended globs are disabled by default. You can use &lt;code&gt;shopt -s extglob&lt;/code&gt; and &lt;code&gt;shopt -u extglob&lt;/code&gt; to set and unset this option respectively.&lt;/p&gt;
&lt;p&gt;Here are some examples (visit &lt;a href="https://github.com/learnbyexample/cli-computing/raw/master/example_files/scripts/globs.sh"&gt;globs.sh&lt;/a&gt; to get the script used below).&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ source globs.sh
&lt;/span&gt;&lt;span&gt;$ ls
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;.sh   f1.txt      f4.txt    hi.sh   math.h         report&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;02&lt;/span&gt;&lt;span&gt;.log
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42&lt;/span&gt;&lt;span&gt;.txt   f2_old.txt  f7.txt    ip.txt  notes.txt      report&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;04&lt;/span&gt;&lt;span&gt;.log
&lt;/span&gt;&lt;span&gt;calc.py  f2.txt      hello.py  main.c  report&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;00&lt;/span&gt;&lt;span&gt;.log  report&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;98&lt;/span&gt;&lt;span&gt;.log
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# one or more digits followed by '.' and then zero or more characters
&lt;/span&gt;&lt;span&gt;$ ls &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;+&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;9&lt;/span&gt;&lt;span&gt;]).&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;.sh  &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42&lt;/span&gt;&lt;span&gt;.txt
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# same as: ls *.c *.sh
&lt;/span&gt;&lt;span&gt;$ ls &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;.@(c&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt;sh)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;.sh  hi.sh  main.c
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# not ending with '.txt'
&lt;/span&gt;&lt;span&gt;$ ls &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;.txt)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;.sh   hello.py  main.c  report&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;00&lt;/span&gt;&lt;span&gt;.log  report&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;04&lt;/span&gt;&lt;span&gt;.log
&lt;/span&gt;&lt;span&gt;calc.py  hi.sh     math.h  report&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;02&lt;/span&gt;&lt;span&gt;.log  report&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;98&lt;/span&gt;&lt;span&gt;.log
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# not ending with '.txt' or '.log'
&lt;/span&gt;&lt;span&gt;$ ls &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;!&lt;/span&gt;&lt;span&gt;(txt&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt;log)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;.sh  calc.py  hello.py  hi.sh  main.c  math.h
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/cli-computing"&gt;Linux Command Line Computing&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 23 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-19/</guid></item><item><title>A Programmer-Friendly I/O Abstraction Over io_uring and kqueue</title><link>http://notes.eatonphil.com/a-friendly-abstraction-over-iouring-and-kqueue.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://tigerbeetle.com/blog/a-friendly-abstraction-over-iouring-and-kqueue/"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Wed, 23 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/a-friendly-abstraction-over-iouring-and-kqueue.html</guid></item><item><title>Gonna use a personal trick/hack? Use it often</title><link>/2022/11/22/Gonna-use-a-personal-trick/hack-Use-it-often/</link><description>&lt;p&gt;What do I mean by trick/hack? This can be super flexible, but I’ll toss out a few of my own personal ones.&lt;/p&gt;
&lt;p&gt;One of the rules of my product management philosophy, is if you’re going to use a tool or trick then use it often. This is in fact one of my favorite interview questions for PMs. If you ever interview with me, be prepared it’s coming. It applies for engineering managers and others in leadership roles as well, but I’ve found especially get for PMs.&lt;/p&gt;
&lt;h3 id="getting-a-response-from-team-emails"&gt;
&lt;div&gt;
Getting a response from team emails
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;It’s very common to have a team@ alias within your company, whether for the whole team or for smaller teams. As a PM you may need to email sales@ and get feedback of requested features, or feedback on the roadmap. Chances are you’ll send some good time and effort crafting this email, being concise but also giving enough context for them to give you an informed response. If you’re good you’ve fed the email through hemingway app before you sent it and gotten it down to grade level 7 or lower. You send it middle on a Tuesday around 10am so it’s not lost in Monday triage, and not missed on Thursday that aligns to a long holiday weekend. And then… silence. Nothing. Nada. Zip. Zilch.&lt;/p&gt;
&lt;p&gt;I’m not really sure the reason for crickets, perhaps at best they assumed a bunch of their peers got back to you privately. At worst they’re apathetic and care strictly on closing their next deal and not giving feedback that helps long term growth. But I’m not here to dissect why. How do you get a response?&lt;/p&gt;
&lt;p&gt;Slightly restructure the email to instead of going to the sales@ alias, be targeted to individuals. Pull the emails of everyone on the list, make the opening a generic “Hi,”, and have it go directly to the individuals via a mail merge.&lt;/p&gt;
&lt;p&gt;From experience have had CEOs (who I forgot to omit) email me back when they were out on vacation apologizing for slow response (of hours) and that they’d get me feedback before weeks end.&lt;/p&gt;
&lt;h3 id="turn-a-group-email-into-a-love-fest"&gt;
&lt;div&gt;
Turn a group email into a love fest
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;As much as 1:1 emails are great and will solicit a response. Often you need to send out an announcement to a team. “We’ve got a big announcement tomorrow”. You’ll put the same work and effort into that team email as you did in the above, and again the usual response is crickets.&lt;/p&gt;
&lt;p&gt;My teams know I do this, and yet it still works. Get 1-2 other leaders (not necessarily management) but morale leaders to know it’s coming and chime in on a reply-all to the team@ list with positive comments and praise. The same applies also to new hire announcements that goes to team@. You’re going to end up with folks not wanting to be left out from piling on. It’ll start to get flow of feedback public and private coming in about what is good on the communication and give you a sense of where it can improve.&lt;/p&gt;
&lt;h3 id="what-are-your-hacks"&gt;
&lt;div&gt;
What are your hacks?
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;These are just a few, as I keep writing up some longer form of my personal product philosophies will layer in more of these nuggets. But every good PM I’ve ever worked with has had their own bag of tricks. Again it’s one of my favorite interview questions, I’ve stolen many great tricks from others over the years. But curious, even without needing for us to be in an interview what are yours? @&lt;a href="https://www.twitter.com/craigkerstiens"&gt;craigkerstiens&lt;/a&gt;&lt;/p&gt;</description><author>CRAIG KERSTIENS</author><pubDate>Tue, 22 Nov 2022 18:11:56 GMT</pubDate><guid isPermaLink="true">/2022/11/22/Gonna-use-a-personal-trick/hack-Use-it-often/</guid></item><item><title>Building a custom code search index in Go for searchcode.com</title><link>https://boyter.org/posts/how-i-built-my-own-index-for-searchcode/</link><description>&lt;h1 id="abstract-tldr"&gt;Abstract TL/DR&lt;/h1&gt;
&lt;p&gt;I present what I belive is a unique index for indexing and searching source code. It copies ideas from Bing bitfunnel implementation to create a very fast, memory efficient trigram index over source code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;searchcode.com is now using a custom built index written by yours truly&lt;/li&gt;
&lt;li&gt;It indexes 180-200 million documents and 75 billions lines of code&lt;/li&gt;
&lt;li&gt;The index works using bloom filters sharded by unique document trigrams&lt;/li&gt;
&lt;li&gt;It borrows some of the core ideas of bitfunnel used in microsoft&amp;rsquo;s bing&lt;/li&gt;
&lt;li&gt;The use of trigrams inside a bloom filter search is as far as I can tell unique&lt;/li&gt;
&lt;li&gt;It lowered the index search times from many seconds to ~40ms across searchcode&lt;/li&gt;
&lt;li&gt;End user searches still take around 300 ms to process though&lt;/li&gt;
&lt;li&gt;It also improved search relevance and reliability&lt;/li&gt;
&lt;li&gt;Architecture wise things became simpler, as the new index sits on a single machine not four&lt;/li&gt;
&lt;li&gt;It uses caddy as the reverse proxy and redis as a level 2 cache&lt;/li&gt;
&lt;li&gt;The index sits entirely in memory on a 16 core 5950x CPU and 128 GB RAM machine&lt;/li&gt;
&lt;li&gt;It currently processes close to a million searches every day&lt;/li&gt;
&lt;li&gt;I also gave the site a new look and feel which is much better than what it looked like previously&lt;/li&gt;
&lt;li&gt;I had an absolute blast learning and building it&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="what-happened"&gt;What Happened?&lt;/h1&gt;
&lt;p&gt;On Monday 21st November 2022 I updated the DNS entries for searchcode to point at the new searchcode server running a custom implemented index, ending the reliance on sphinx/manticore in order to power searches. Since being released I have observed it run over 1 million searches a day with a rolling average runtime of ~40 ms for replacement index.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Tue, 22 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/how-i-built-my-own-index-for-searchcode/</guid></item><item><title>AWS may have broken your Cloudfront API for nearly a month</title><link>https://tomforb.es/blog/aws-broke-your-api/</link><description>tl;dr : If you rely on the x-forwarded-for header with Cloudfront and have enabled Origin Shield, between October the 10th 2022 and November the 2nd 2022 the value of this header may have been incorrect for a percentage of requests. If your API relies on knowing the clients IP address in any way it ...</description><author>Tom Forbes</author><pubDate>Sun, 20 Nov 2022 23:42:54 GMT</pubDate><guid isPermaLink="true">https://tomforb.es/blog/aws-broke-your-api/</guid></item><item><title>Deep Into Technical Debt</title><link>https://cmdev.com/blog/deep-into-technical-debt/</link><description>Technical debt is anything done today knowing it will make code harder to change later</description><author>The Cranky Developer on Crater Moon Development</author><pubDate>Sat, 19 Nov 2022 20:00:00 GMT</pubDate><guid isPermaLink="true">https://cmdev.com/blog/deep-into-technical-debt/</guid></item><item><title>On the impending loss of Twitter, and the value of social graphs</title><link>https://mikewarot.blogspot.com/2022/11/on-impending-loss-of-twitter-and-value.html</link><description>&lt;p&gt;Well, with the impending demise of Twitter, it looks like I'll be following &lt;a href="https://nice-marmot.net/" target="_blank"&gt;Dave Rogers&lt;/a&gt;, and the rest of the world, on RSS again, along with everyone else. I've got a list... it's about 250 entries long, that will make the start of my RSS feeds.&lt;br /&gt;&lt;br /&gt;Twitter had an immediacy that RSS lacks, having solved the problem of feedback by outsourcing the policing of spam, etc. to a staff that has been let go.&lt;br /&gt;&lt;br /&gt;I like seeing what the people I follow are saying, but the idea of retweeting at a click was seductive, but a bit &lt;i&gt;too easy&lt;/i&gt;&amp;nbsp;because you never say WHY you retweet someone, you're just blindly sharing an idea without adding any &lt;i&gt;&lt;b&gt;new&lt;/b&gt;&lt;/i&gt; context.&lt;/p&gt;&lt;p&gt;I can't help but feel that if &lt;a href="http://www.aaronsw.com/" target="_blank"&gt;Aaron Swartz&lt;/a&gt; were still with us, he'd have figured out something more powerful, open source, and wonderful to replace Twitter at this time.&lt;/p&gt;&lt;p&gt;In losing Twitter, I lose links to the comments of friends now gone like &lt;a href="https://twitter.com/michaelocc" target="_blank"&gt;Michael O'Connor Clarke&lt;/a&gt;, and they likely aren't archived anywhere else, except the &lt;a href="https://web.archive.org/web/20150721064240/http://www.michaelocc.com:80/" target="_blank"&gt;Internet Archive of his blog&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I've suffered my own health issues, and this loss (or threat) of Twitter just serves to remind me of the things I'm thankful for, friends and family I've shared this journey with.&lt;br /&gt;&lt;br /&gt;I've yet to pick out an RSS reader....I'll post here when I do.&lt;br /&gt;&lt;br /&gt;[Update] &lt;a href="http://www.rssowl.org/" target="_blank"&gt;RSSowl&lt;/a&gt; seems to be a usable, locally installed and run Desktop OS RSS Reader. It's only quirk is that it needs the 32 bit Java runtime, regardless of your 64 bit OS, etc.&amp;nbsp;&lt;/p&gt;</description><author>--Mike--</author><pubDate>Fri, 18 Nov 2022 19:50:47 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/11/on-impending-loss-of-twitter-and-value.html</guid></item><item><title>Zsh Configuration and Plugins - Part Two</title><link>https://smcleod.net/2022/11/zsh-configuration-and-plugins-part-two/</link><description>My Z-Shell configuration, scripts and hacks</description><author>smcleod.net</author><pubDate>Fri, 18 Nov 2022 07:32:43 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/11/zsh-configuration-and-plugins-part-two/</guid></item><item><title>Fred Brooks</title><link>https://cmdev.com/blog/fred-brooks/</link><description>Frederick P.Brooks Jr., April 19, 1931 – November 17, 2022</description><author>The Cranky Developer on Crater Moon Development</author><pubDate>Fri, 18 Nov 2022 06:59:33 GMT</pubDate><guid isPermaLink="true">https://cmdev.com/blog/fred-brooks/</guid></item><item><title>Python tip 19: manipulating string case</title><link>https://learnbyexample.github.io/tips/python-tip-19/</link><description>&lt;p&gt;Here are five string methods you can use for changing the case of characters. Word level transformation is determined by consecutive occurrences of alphabets, not limited to separation by whitespace characters.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'thIs iS a saMple StrIng'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;capitalize&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'This is a sample string'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;title&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'This Is A Sample String'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;lower&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'this is a sample string'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;upper&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'THIS IS A SAMPLE STRING'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;swapcase&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'THiS Is A SAmPLE sTRiNG'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;string.capwords()&lt;/code&gt; method is similar to &lt;code&gt;title()&lt;/code&gt; but also allows a specific separator (default is whitespace).&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; import &lt;/span&gt;&lt;span&gt;string
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;phrase &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'this-IS-a:colon:separated,PHRASE'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# every word is transformed
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;phrase.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;title&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'This-Is-A:Colon:Separated,Phrase'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# colon character is used as the text boundary
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;string.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;capwords&lt;/span&gt;&lt;span&gt;(phrase, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;':'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'This-is-a:Colon:Separated,phrase'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 16 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-19/</guid></item><item><title>Infosys leaked FullAdminAccess AWS keys on PyPi for over a year</title><link>https://tomforb.es/blog/infosys-leak/</link><description>You can check out their website for a lot of buzwords , but it’s clear from all the stock photos that they take security Very Seriously Indeed ™️. However, from what I’ve found recently, it seems that Infosys use the following Comprehensive Management-Endorsed Proficiently Driven Cybersecurity Strat...</description><author>Tom Forbes</author><pubDate>Wed, 16 Nov 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://tomforb.es/blog/infosys-leak/</guid></item><item><title>What is the Highfleet Ship Optimizer?</title><link>https://jodavaho.io/posts/hfopt-intro.html</link><description>&lt;h2 id="building-a-highfleet-ship-optimizer"&gt;Building a highfleet ship optimizer&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Me and &lt;a href="https://github.com/altho"&gt;Altho&lt;/a&gt; built, essentially, a cogitator for your dieselpunk legos game.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Highfleet (&lt;a href="http://koshutin.com/"&gt;koshutin.com&lt;/a&gt;) is a game by Konstantin
Koshutin, of Hammerflight fame. In that game you have to bulid, peice by peice,
huge rocket-propelled fleets to fight above a primitive desert society. The
attention to detail is immaculate. Radio communications, electronic
intelligence / warfare, and strike fleet management are just the tip of the
iceburg. It&amp;rsquo;s great fun, for engineers especially.&lt;/p&gt;
&lt;p&gt;What gets most people addicted, however, is the ship editing. You can create
and build ships from a suprisingly few number of modules that become highly
individualized / specialized. This gif (from &lt;a href="http://koshutin.com/"&gt;koshutin.com&lt;/a&gt;) shows the design loop perfectly:&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://jodavaho.io/img/design.gif" /&gt;&lt;figcaption&gt;
      &lt;h4&gt;Highfleet ship design from koshutin.com&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;But seriously, check out that page, the game is beautiful.
The most challenging part of building a &lt;em&gt;good&lt;/em&gt; ship, is keeping the number of
extra modules low, and selecting the appropriate modules to keep the cost low
and performance high.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been working on an optimizer to help. This codebase selects modules from
the game Highfleet, such that desired in-game statistics are satisfied. It does
so optimally and fast, using state-of-the-art solver library SCIP.&lt;/p&gt;
&lt;p&gt;This project is free, and hosted on
&lt;a href="https://hfopt.jodavaho.io"&gt;hfopt.jodavaho.io&lt;/a&gt; if you&amp;rsquo;d like to give it a shot.&lt;/p&gt;
&lt;p&gt;Most use cases are one of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I have a number of weapons and sensor that I&amp;rsquo;d like to include, but don&amp;rsquo;t know the best set of engines and support modules to optimally include them&lt;/li&gt;
&lt;li&gt;I have a scout ship in mind, one that can go a certain speed and travel a certain range with a few sensors.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m curious what is the cheapest ship that can accomodate a given weapon or sensor, given a speed, weight, range, or other constraint&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As always, please feel free to file issues here with questions, suggestions, or bugs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I especially need help verifying the stats of the output modules, once combined&lt;/strong&gt;. The math behind the game is notoriously opaque, and all the stats used were compiled from &lt;a href="https://reddit.com/r/highfleet"&gt;reddit.com/r/highfleet&lt;/a&gt;, esp &lt;code&gt;/u/d0d0b1rd&lt;/code&gt; and &lt;code&gt;/u/twiglard&lt;/code&gt;.&lt;/p&gt;</description><author>jodavaho.io</author><pubDate>Mon, 14 Nov 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://jodavaho.io/posts/hfopt-intro.html</guid></item><item><title>Computing from the Command Line: sales report</title><link>https://learnbyexample.github.io/mini/cli-computing-sales/</link><description>&lt;p&gt;I've previously written about events and strategies that led to &lt;a href="https://learnbyexample.github.io/wild-ride-2021/#book-sales"&gt;increased ebook sales during the last quarter of 2021&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Very pleased to inform that I continue to see more than expected sales during release week. My 13th ebook &lt;a href="https://github.com/learnbyexample/cli-computing"&gt;Computing from the Command Line&lt;/a&gt; was published on November 1st. Here's how the sales looked on Gumroad during the first ten days:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Ten days Gumroad sales chart" src="/images/cli-computing-release-gumroad-sales.png" /&gt;&lt;/p&gt;
&lt;p&gt;I used to offer my ebooks for free on release. For the past few releases, I have also added heavily discounted ebook bundles which seems to be the major factor in increased paid sales I'm seeing. Luck certainly plays a role too in reaching users through social media. Here are some of the ways I promoted my latest ebook:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.gumroad.com/p/announcing-computing-from-the-command-line-free-discount-offers-and-more"&gt;Announcement post on Gumroad&lt;/a&gt; and sending an email to existing readers (1000+ users opened the email as per Gumroad analytics)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/learn_byexample/status/1587443517823275009"&gt;Pinned tweet&lt;/a&gt; — more than 300 link clicks as per Twitter analytics&lt;/li&gt;
&lt;li&gt;Posting on &lt;a href="https://old.reddit.com/r/commandline/comments/yk1izp/i_wrote_a_book_on_linux_cli_tools_and_shell/"&gt;/r/commandline/&lt;/a&gt;, &lt;a href="https://old.reddit.com/r/linux/comments/yk1n8y/i_wrote_a_book_on_linux_cli_tools_and_shell/"&gt;/r/linux/&lt;/a&gt;, &lt;a href="https://old.reddit.com/r/linux4noobs/comments/ykzuia/i_wrote_a_book_on_linux_cli_tools_and_shell/"&gt;/r/linux4noobs/&lt;/a&gt; and &lt;a href="https://old.reddit.com/r/FreeEBOOKS/comments/yoj33g/computing_from_the_command_line_linux_tools_and/"&gt;/r/FreeEBOOKS/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=33449401"&gt;Show HN post on Hacker News&lt;/a&gt; — wasn't lucky this time to reach front page&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/PS5XEemn164"&gt;Promo video on youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mentioned in my &lt;a href="https://learnbyexample.gumroad.com/l/learnbyexample-weekly"&gt;learnbyexample weekly&lt;/a&gt; newsletter&lt;/li&gt;
&lt;li&gt;And of course, I wrote a release post &lt;a href="https://learnbyexample.github.io/computing-from-the-command-line-announcement/"&gt;on this blog&lt;/a&gt; and also mentioned it on my &lt;a href="https://github.com/learnbyexample"&gt;GitHub Readme&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Apart from Gumroad, 400+ readers downloaded the ebook from &lt;a href="https://leanpub.com/cli_computing"&gt;Leanpub&lt;/a&gt; and I got a few paid sales as well. I wrote about &lt;a href="https://learnbyexample.github.io/my-book-writing-experience/#leanpub-vs-gumroad"&gt;pros and cons of Gumroad/Leanpub here&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; PS: Make sure to read the rules and be a regular user before self-promoting your content on the social media platforms mentioned above.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Mon, 14 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/mini/cli-computing-sales/</guid></item><item><title>Writing a SQL database, take two: Zig and RocksDB</title><link>http://notes.eatonphil.com/zigrocks-sql.html</link><description>&lt;p&gt;For my second project while learning Zig, I decided to port an
old, minimal SQL database project from Go to Zig.&lt;/p&gt;
&lt;p&gt;In this post, in ~1700 lines of code (yes, I'm sorry it's bigger than
my usual), we'll create a basic embedded SQL database in Zig on top of
RocksDB. Other than the RocksDB layer it will not use third-party
libraries.&lt;/p&gt;
&lt;p&gt;The code for this project is available on &lt;a href="https://github.com/eatonphil/zigrocks"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here are a few example interactions we'll support:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--database data --script &amp;lt;(echo &amp;quot;CREATE TABLE y (year int, age int, name text)&amp;quot;)&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;CREATE TABLE y (year int, age int, name text)&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--database data --script &amp;lt;(echo &amp;quot;INSERT INTO y VALUES (2010, 38, 'Gary')&amp;quot;)&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;INSERT INTO y VALUES (2010, 38, 'Gary')&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--database data --script &amp;lt;(echo &amp;quot;INSERT INTO y VALUES (2021, 92, 'Teej')&amp;quot;)&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;INSERT INTO y VALUES (2021, 92, 'Teej')&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--database data --script &amp;lt;(echo &amp;quot;INSERT INTO y VALUES (1994, 18, 'Mel')&amp;quot;)&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;INSERT INTO y VALUES (1994, 18, 'Mel')&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt;

&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Basic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--database data --script &amp;lt;(echo &amp;quot;SELECT name, age, year FROM y&amp;quot;)&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;SELECT name, age, year FROM y&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="k"&gt;year&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;====&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;+===&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;+====&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mel&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;1994&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gary&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;2010&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Teej&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;

&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;With&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--database data --script &amp;lt;(echo &amp;quot;SELECT name, year, age FROM y WHERE age &amp;lt; 40&amp;quot;)&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;SELECT name, year, age FROM y WHERE age &amp;lt; 40&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="k"&gt;year&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;====&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;+====&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;+===&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mel&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;1994&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gary&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;2010&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;

&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;With&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;operations&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--database data --script &amp;lt;(echo &amp;quot;SELECT 'Name: ' || name, year + 30, age FROM y WHERE age &amp;lt; 40&amp;quot;)&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;SELECT 'Name: ' || name, year + 30, age FROM y WHERE age &amp;lt; 40&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unknown&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="k"&gt;unknown&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=======&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="o"&gt;+=======&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;+===&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mel&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Gary&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;2040&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This post is standalone (except for the RocksDB layer which I &lt;a href="https://notes.eatonphil.com/zigrocks.html"&gt;wrote
about here&lt;/a&gt;) but it builds on a
number of ideas I've explored that you may be interested in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://notes.eatonphil.com/whats-the-big-deal-about-key-value-databases.html"&gt;What's the big deal about key-value databases like FoundationDB and RocksDB?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://notes.eatonphil.com/distributed-postgres.html"&gt;Let's build a distributed Postgres proof of concept&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://notes.eatonphil.com/documentdb.html"&gt;Writing a document database from scratch in Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;And the grandfather series, &lt;a href="https://notes.eatonphil.com/database-basics.html"&gt;Writing a SQL database from scratch in Go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This project is mostly a port of my &lt;a href="https://notes.eatonphil.com/database-basics.html"&gt;SQL database from scratch in
Go&lt;/a&gt; project, but
unlike that series this project will have persistent storage via
RocksDB.&lt;/p&gt;
&lt;p&gt;And unlike that post, this project is written in Zig!&lt;/p&gt;
&lt;p&gt;Let's get started. :)&lt;/p&gt;
&lt;h3 id="components"&gt;Components&lt;/h3&gt;&lt;p&gt;We're going to split up the project into the following major
components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lexing&lt;/li&gt;
&lt;li&gt;Parsing&lt;/li&gt;
&lt;li&gt;Storage&lt;ul&gt;
&lt;li&gt;RocksDB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Execution&lt;/li&gt;
&lt;li&gt;Entrypoint (&lt;code&gt;main&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Lexing&lt;/em&gt; takes a query and breaks it into an array of tokens.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Parsing&lt;/em&gt; takes the lexed array of tokens and pattern matches into a
syntax tree (AST).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Storage&lt;/em&gt; maps high-level SQL entities like tables and rows into bytes
that can be easily stored on disk. And it handles recovering
high-level tables and rows from bytes on disk.&lt;/p&gt;
&lt;p&gt;Invisible to users of the &lt;em&gt;Storage&lt;/em&gt; component is &lt;em&gt;RocksDB&lt;/em&gt;, which is how
the bytes are actually stored on disk. &lt;a href="http://rocksdb.org/"&gt;RocksDB&lt;/a&gt; is a persistent store
that maps arbitary byte keys to arbitrary byte values. We'll use it
for storing and recovering both table metadata and actual row data.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Execution&lt;/em&gt; takes a query AST and executes it against &lt;em&gt;Storage&lt;/em&gt;,
potentially returning result rows.&lt;/p&gt;
&lt;p&gt;These terms are a vast simplification of real-world database
design. But they are helpful structure to have even in a project
this small.&lt;/p&gt;
&lt;h3 id="memory-management"&gt;Memory Management&lt;/h3&gt;&lt;p&gt;Zig doesn't have a garbage collector. Mitchell Hashimoto &lt;a href="https://github.com/mitchellh/zig-libgc"&gt;wrote
bindings to Boehm GC&lt;/a&gt;. But Zig
also has a &lt;a href="https://ziglang.org/documentation/master/#toc-Choosing-an-Allocator"&gt;builtin Arena
allocator&lt;/a&gt;
which is perfect for this simple project.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; function will create the arena and pass it to each
component, where they can do allocations as they please. At the end of
&lt;code&gt;main&lt;/code&gt;, the entire arena will be freed at once.&lt;/p&gt;
&lt;p&gt;The only other place where we must do manual memory management is in
the RocksDB wrapper. But &lt;a href="https://notes.eatonphil.com/zigrocks.html"&gt;I've already
covered&lt;/a&gt; that in a separate
post.&lt;/p&gt;
&lt;h3 id="zig-specifics"&gt;Zig Specifics&lt;/h3&gt;&lt;p&gt;I'm not going to cover the basics of Zig syntax. If you are new to
Zig, read &lt;a href="https://notes.eatonphil.com/zigrocks.html"&gt;this&lt;/a&gt; first!
(It's short.)&lt;/p&gt;
&lt;p&gt;Now that we've got the basic idea, we can start coding!&lt;/p&gt;
&lt;h3 id="types-(&amp;lt;code&amp;gt;types.zig&amp;lt;/code&amp;gt;,-10-loc)"&gt;Types (&lt;code&gt;types.zig&lt;/code&gt;, 10 LoC)&lt;/h3&gt;&lt;p&gt;Let's create a few helper types that we'll use in the rest of the
code.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;comptime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it. :) Makes things a little more readable.&lt;/p&gt;
&lt;h3 id="lexing-(&amp;lt;code&amp;gt;lex.zig&amp;lt;/code&amp;gt;,-308-loc)"&gt;Lexing (&lt;code&gt;lex.zig&lt;/code&gt;, 308 LoC)&lt;/h3&gt;&lt;p&gt;Lexing turns a query string into an array of tokens.&lt;/p&gt;
&lt;p&gt;There are a few &lt;em&gt;kinds&lt;/em&gt; of tokens we'll define:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keywords (like &lt;code&gt;CREATE&lt;/code&gt;, &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;)&lt;ul&gt;
&lt;li&gt;Syntax (commas, parentheses, operators, and all other builtin symbols)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Strings&lt;/li&gt;
&lt;li&gt;Integers&lt;/li&gt;
&lt;li&gt;Identifiers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And not listed there but important to &lt;em&gt;skip past&lt;/em&gt; is whitespace.&lt;/p&gt;
&lt;p&gt;Let's turn this into a Zig struct!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;std&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;types.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;types.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Keywords&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;select_keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;create_table_keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;insert_keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;values_keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;from_keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;where_keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Operators&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;plus_operator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;equal_operator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;lt_operator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;concat_operator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Other syntax&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;left_paren_syntax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;right_paren_syntax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;comma_syntax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Literals&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using an &lt;code&gt;enum&lt;/code&gt; helps us with type safety. And since we're storing
location in the token, we can build a nice debug function for when
lexing or parsing fails.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lineStartIndex&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lineEndIndex&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;lineStartIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// Find the end of the line&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;lineEndIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lineEndIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;lineEndIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lineEndIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{s}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Near line {}, column {}.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;{s}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lineStartIndex&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;lineEndIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;^ Near here&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And similarly, let's add a debug helper for when we're dealing with an
array of tokens.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;preferredIndex&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;preferredIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="token-&amp;lt;&amp;gt;-string-mapping"&gt;Token &amp;lt;&amp;gt; String Mapping&lt;/h4&gt;&lt;p&gt;Before we get too far from &lt;code&gt;Token&lt;/code&gt; definition, let's define a mapping
from the &lt;code&gt;Token.kind&lt;/code&gt; enum to strings we can see in a query.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Builtin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// These must be sorted by length of the name text, descending, for lexKeyword.&lt;/span&gt;
&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BUILTINS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;Builtin&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CREATE TABLE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_table_keyword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;INSERT INTO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert_keyword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SELECT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_keyword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;VALUES&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values_keyword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;WHERE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where_keyword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;FROM&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_keyword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;||&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concat_operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;equal_operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plus_operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lt_operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;(&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left_paren_syntax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right_paren_syntax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comma_syntax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We'll use this in a few lexing functions below.&lt;/p&gt;
&lt;h4 id="whitespace"&gt;Whitespace&lt;/h4&gt;&lt;p&gt;Outside of tokens, we need to be able to skip past whitespace.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;' '&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;'\n'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;'\t'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;'\r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All lexing functions will look like this. They'll take the source as
one argument and a cursor to the current index in the source as
another.&lt;/p&gt;
&lt;h4 id="keywords"&gt;Keywords&lt;/h4&gt;&lt;p&gt;Let's handle lexing keyword tokens next. Keywords are case
insensitive. I don't think there's a builtin case insensitive string
comparison function in Zig. So let's write that first.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;asciiCaseInsensitiveEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;97&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;97&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately it only supports ASCII for now.&lt;/p&gt;
&lt;p&gt;Now we can write a simple longest-matching-substring function. It is
simple because the keyword mapping we set up above is already ordered
by length descending.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexKeyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;longestLen&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_keyword&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BUILTINS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asciiCaseInsensitiveEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;longestLen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// First match is the longest match&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;longestLen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;longestLen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;longestLen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it!&lt;/p&gt;
&lt;h4 id="integers"&gt;Integers&lt;/h4&gt;&lt;p&gt;For integers we read through the source until we stop seeing
decimal digits. Obviously this is a subset of what people consider
integers, but it will do for now!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'9'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="strings"&gt;Strings&lt;/h4&gt;&lt;p&gt;Strings are enclosed in single quotes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;'\''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;'\''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;'\''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="identifiers"&gt;Identifiers&lt;/h4&gt;&lt;p&gt;Identifiers for this project are alphanumeric characters. We could
support more by optionally checking for double quote enclosed
strings. But I'll leave that as an exercise for the reader.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'a'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'z'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'A'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'Z'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="&amp;lt;code&amp;gt;lex&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;lex&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;Now we can pull together all these helper functions in a public
entrypoint for lexing.&lt;/p&gt;
&lt;p&gt;It will loop through a query string, eating whitespace and checking
for tokens. It will continue until it hits the end of the query
string. If it ever can't continue it fails.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keywordRes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexKeyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywordRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to allocate space for keyword token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keywordRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;integerRes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;integerRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to allocate space for integer token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;integerRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringRes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stringRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to allocate space for string token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;identifierRes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identifierRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to allocate space for identifier token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;identifierRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Last good token.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Bad token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it for lexing! Now we can do parsing.&lt;/p&gt;
&lt;h3 id="parsing-(&amp;lt;code&amp;gt;parse.zig&amp;lt;/code&amp;gt;,-407-loc)"&gt;Parsing (&lt;code&gt;parse.zig&lt;/code&gt;, 407 LoC)&lt;/h3&gt;&lt;p&gt;Parsing takes an array of tokens from the lexing stage and discovers
the tree structure in them that maps to a predefined syntax tree
(AST).&lt;/p&gt;
&lt;p&gt;If it can't discover a valid tree from the array of tokens, it fails.&lt;/p&gt;
&lt;p&gt;Let's set up the basics of the &lt;code&gt;Parser&lt;/code&gt; struct:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;std&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;lex.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;types.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;index&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="expressions"&gt;Expressions&lt;/h4&gt;&lt;p&gt;Expressions are at the bottom of the syntax tree.&lt;/p&gt;
&lt;p&gt;They can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Literals (like strings, integers, booleans, etc.)&lt;/li&gt;
&lt;li&gt;Or binary operations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's define these in Zig:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BinaryOperationAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BinaryOperationAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; {s} &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;binary_operation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BinaryOperationAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;'{s}'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()}),&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{s}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()}),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary_operation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary_operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can attempt to parse either of these from an array of tokens.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parseExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;No expression&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;equal_operator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lt_operator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plus_operator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concat_operator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary_operation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BinaryOperationAST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for left expression.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for right expression.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;newE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary_operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary_operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Basically, we assume it's a literal expression unless we see an
operator after it. If there's an operator after it we call
&lt;code&gt;parseExpression&lt;/code&gt; recursively and return a binary expression.&lt;/p&gt;
&lt;p&gt;Important to note: this skips both implicit operator precedence and
explicit precedence via parenthesis.&lt;/p&gt;
&lt;h4 id="&amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;SELECT&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;A &lt;code&gt;SELECT&lt;/code&gt; query's structure has a &lt;code&gt;FROM&lt;/code&gt; table name, a
comma-separated list of expressions, and an optional &lt;code&gt;WHERE&lt;/code&gt; section
with another expression for the where.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SelectAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SelectAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SELECT&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;  &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;FROM&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;  {s}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()});&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;WHERE&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;  &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To parse it we look for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SELECT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Then a comma separated list of &lt;code&gt;ExpressionAST&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;Then a &lt;code&gt;FROM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Then optionally a &lt;code&gt;WHERE&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;And then another &lt;code&gt;ExpressionAST&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the help of &lt;code&gt;expectTokenKind&lt;/code&gt; and &lt;code&gt;parseExpression&lt;/code&gt; it is not too
difficult, but a little verbose, to write.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parseSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected SELECT keyword&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SelectAST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Parse columns&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comma_syntax&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected comma.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected comma.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for token.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected FROM keyword after this.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected FROM keyword&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected FROM table name after this.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected FROM keyword&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// i + 1, skip past the where&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unexpected token.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Did not complete parsing SELECT&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it!&lt;/p&gt;
&lt;h4 id="&amp;lt;code&amp;gt;create-table&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;CREATE TABLE&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;A &lt;code&gt;CREATE TABLE&lt;/code&gt; query's structure has a table name and a list of
comma separated identifier pairs for column name and kind.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreateTableColumnAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreateTableAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;CreateTableColumnAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreateTableAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CREATE TABLE {s} (&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;  {s} {s}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To parse it we look for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CREATE TABLE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Followed by an identifier (the table name)&lt;/li&gt;
&lt;li&gt;Followed by open parenthesis&lt;/li&gt;
&lt;li&gt;Followed by a comma separated list of identifier pairs&lt;/li&gt;
&lt;li&gt;Followed by close parenthesis&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parseCreateTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_table_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected CREATE TABLE keyword&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected table name after CREATE TABLE keyword.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected CREATE TABLE name&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateTableColumnAST&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreateTableAST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left_paren_syntax&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected opening paren after CREATE TABLE name.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected opening paren&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right_paren_syntax&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comma_syntax&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected comma.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected comma.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreateTableColumnAST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected column name after comma.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected identifier.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected column type after column name.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected identifier.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for column.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Skip past final paren.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unexpected token.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Did not complete parsing CREATE TABLE&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="&amp;lt;code&amp;gt;insert-into&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;INSERT INTO&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;And last we've got &lt;code&gt;INSERT INTO&lt;/code&gt;. This tree has table name and a list
of expressions to insert into the table.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InsertAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InsertAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;INSERT INTO {s} VALUES (&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We parse it by looking for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSERT INTO&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Followed by a table name&lt;/li&gt;
&lt;li&gt;Followed by &lt;code&gt;VALUES&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Followed by open parenthesis&lt;/li&gt;
&lt;li&gt;Followed by a comma-separated list of expressions&lt;/li&gt;
&lt;li&gt;Followed by a close parenthesis&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parseInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected INSERT INTO keyword&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected table name after INSERT INTO keyword.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected INSERT INTO table name&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InsertAST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected VALUES keyword.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected VALUES keyword&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left_paren_syntax&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected opening paren after CREATE TABLE name.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected opening paren&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right_paren_syntax&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comma_syntax&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected comma.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected comma.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for expression.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Skip past final paren.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unexpected token.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Did not complete parsing INSERT INTO&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="&amp;lt;code&amp;gt;ast&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;AST&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;Finally we can define the top-level SQL &lt;code&gt;AST&lt;/code&gt; as being the union of
the above three query types.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SelectAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InsertAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CreateTableAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we can implement &lt;code&gt;parse&lt;/code&gt; by switching on the current token.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_table_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseCreateTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectTokenKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert_keyword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown statement&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Perfect. For today. :)&lt;/p&gt;
&lt;h3 id="storage-(&amp;lt;code&amp;gt;storage.zig&amp;lt;/code&amp;gt;,-338-loc)"&gt;Storage (&lt;code&gt;storage.zig&lt;/code&gt;, 338 LoC)&lt;/h3&gt;&lt;p&gt;Next we're going to switch contexts completely and think about how
tables and rows will get serialized into bytes that can be stored on
disk.&lt;/p&gt;
&lt;p&gt;The storage layer will define a few general helpers for correctly
serializing and deserializing strings and numbers:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;std&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rocksdb.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;types.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;types.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;types.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;serializeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comptime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb nb-Type"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;sizeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeIntBig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appendSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deserializeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comptime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readIntBig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;sizeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;serializeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb nb-Type"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;serializeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appendSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deserializeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deserializeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;8.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we'll define the &lt;code&gt;Storage&lt;/code&gt; struct itself. Under the hood it will
use RocksDB to store and recover data on disk.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let's think about storage entities.&lt;/p&gt;
&lt;h4 id="values"&gt;Values&lt;/h4&gt;&lt;p&gt;The fundamental unit in the database is a value, or cell. It can be
either a boolean, an integer, a string, or null.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;null_value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TRUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;null_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since all values are strings in the original query, we'll provide a
&lt;code&gt;fromIntegerString&lt;/code&gt; that we can use to convert.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fromIntegerString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iBytes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we'll define functions to cast values to boolean.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;asBool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;null_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To strings.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;null_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Do nothing&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appendSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appendSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{d}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And to integers.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;asInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;null_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fromIntegerString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And finally the storage layer's core concern: serialization...&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;null_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'1'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appendSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'3'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;serializeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And deserialization.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;'1'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'1'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;'2'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;..]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;'3'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deserializeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;..])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We use a simple, space-inefficient scheme for encoding/decoding to
bytes that can be written to disk.&lt;/p&gt;
&lt;h4 id="rows"&gt;Rows&lt;/h4&gt;&lt;p&gt;Now that we've got values, we can define rows in terms of values. And
we can provide a few helper functions for getting cells by field name.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;cells&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cells&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cellBuffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cellBuffer&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;appendBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// Results are internal buffer views. So make a copy.&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appendSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clearRetainingCapacity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since values are serialized with length prefixes, we can
serialize a row by concatenating all the values together.&lt;/p&gt;
&lt;p&gt;Since we must map to keys and values for RocksDB, we give each row a
key prefix that is the table name. And then we give it a random suffix
to distinguish it from other rows in the table. A more intelligent
design would use the table's primary key as the suffix but we don't
support primary keys yet. (See also, the section on "Mapping SQL to
key-value storage" in &lt;a href="https://notes.eatonphil.com/whats-the-big-deal-about-key-value-databases.html"&gt;What's the big deal about key-value databases
like FoundationDB and
RocksDB?&lt;/a&gt;.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;generateId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;openFileZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/dev/random&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;..];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;writeRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Table name prefix&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;row_{s}_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate row key&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Unique row id&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;generateId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not generate id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appendSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;serializeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for cell&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="rowiter"&gt;RowIter&lt;/h4&gt;&lt;p&gt;Reading rows will be slightly different from writing rows since
reading rows will use an iterator. We will wrap the RocksDB iterator
so the consumer of &lt;code&gt;Storage&lt;/code&gt; only needs to deal with &lt;code&gt;Row&lt;/code&gt;s and
&lt;code&gt;Value&lt;/code&gt;s.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RowIter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RowIter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RowIter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;RowIter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rowBytes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;rowBytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rowBytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deserializeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rowBytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;..]);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appendBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RowIter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It does the opposite of what &lt;code&gt;writeRow&lt;/code&gt; did in terms of deserializing
cells one after another. Again, this works because each cell is
length-prefixed.&lt;/p&gt;
&lt;p&gt;Next we must provide the interface for actually getting a
&lt;code&gt;RowIter&lt;/code&gt;. The only condition for the &lt;code&gt;RowIter&lt;/code&gt; at the moment is that
it contains all rows in the table.&lt;/p&gt;
&lt;p&gt;Since we wrote each row with a table name prefix, we can recover it by
iterating over all rows with that prefix.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getRowIter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RowIter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rowPrefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rowPrefix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;row_{s}_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for row prefix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rowPrefix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tableInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RowIter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tableInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="tables"&gt;Tables&lt;/h4&gt;&lt;p&gt;Finally we've got tables. We must store table metadata: its name,
columns and column types.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We will use a &lt;code&gt;tbl_&lt;/code&gt; prefix instead of &lt;code&gt;row_&lt;/code&gt; prefix for table
metadata. But we'll otherwise encode with the same length-prefixed
concatentations.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;writeTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Table name prefix&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tbl_{s}_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate key for table&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;serializeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for column&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;serializeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for column type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the opposite for decoding.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tableKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tableKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tbl_{s}_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for table prefix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// First grab table info&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columnInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;not_found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;No such table&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columnOffset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columnOffset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columnInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deserializeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columnInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;columnOffset&lt;/span&gt;&lt;span class="p"&gt;..]);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;columnOffset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for column name.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deserializeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columnInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;columnOffset&lt;/span&gt;&lt;span class="p"&gt;..]);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;columnOffset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for column kind.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that's it for storage! Again, we're building on top of the
&lt;a href="https://notes.eatonphil.com/zigrocks.html"&gt;RocksDB layer&lt;/a&gt; I already
wrote about. If you want to see how that works, go for it!&lt;/p&gt;
&lt;p&gt;If you just want the &lt;code&gt;rocksdb.zig&lt;/code&gt; file, grab it from
&lt;a href="https://github.com/eatonphil/zigrocks/blob/7831e390f4044bb999507fd6d0e23bb2475756f8/rocksdb.zig"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="execute-(&amp;lt;code&amp;gt;execute.zig&amp;lt;/code&amp;gt;,-210-loc)"&gt;Execute (&lt;code&gt;execute.zig&lt;/code&gt;, 210 LoC)&lt;/h3&gt;&lt;p&gt;Now that we've got a storage layer and an AST from our parser, we can
execute the query on top of the storage!&lt;/p&gt;
&lt;p&gt;A better implementation might translate the AST to bytecode and
implement a bytecode interpreter for expression evaluation. But we'll
build a tree-walking interpreter instead.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;std&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;parse.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rocksdb.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;storage.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;types.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;types.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In general we'll make query responses optional. They can be empty or
they can be an array of an array of strings (rows and cells) and an
array of strings (column names).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryResponse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Array of cells (which is an array of serde (which is an array of u8))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryResponseResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QueryResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="expressions"&gt;Expressions&lt;/h4&gt;&lt;p&gt;For execution we start again at the bottom with expressions. There are literals.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executeExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExpressionAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromIntegerString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And there are a handful of binary operations.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary_operation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;bin_op&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;equal_operator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// Cast dissimilar types to serde&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;@enumToInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@enumToInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;leftBuf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;leftBuf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;leftBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rightBuf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rightBuf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rightBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;null_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asBool&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blk&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;leftBuf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;leftBuf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rightBuf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rightBuf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;blk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;leftBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rightBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asInteger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asInteger&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concat_operator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lt_operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asInteger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asInteger&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TRUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plus_operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;integer_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asInteger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asInteger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="&amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;SELECT&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;To execute a &lt;code&gt;SELECT&lt;/code&gt; query we first validate the requested table and
requested fields.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executeSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryResponseResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Now validate and store requested fields&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requestedFields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;requestedColumn&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fieldName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestedColumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// TODO: give reasonable names&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;unknown&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// TODO: give reasonable names&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;unknown&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;requestedFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fieldName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for requested field.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then grab an iterator for rows in the table.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requestedFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRowIter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And finally we iterate through all rows and add rows to the response
if there is no &lt;code&gt;WHERE&lt;/code&gt; condition or if we evaluate the &lt;code&gt;WHERE&lt;/code&gt;
condition successfully.&lt;/p&gt;
&lt;p&gt;When we add rows to the response, we need to actually evaluate the
expression for each column in the &lt;code&gt;SELECT&lt;/code&gt; AST.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;asBool&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requested&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valBuf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;valBuf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;requested&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valBuf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for requested cell&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requested&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for row&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="&amp;lt;code&amp;gt;insert-into&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;INSERT INTO&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;Inserting is pretty simple, we just evaluate the &lt;code&gt;VALUES&lt;/code&gt; passed and
write them to storage.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executeInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InsertAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryResponseResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;emptyRow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;emptyRow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for cell&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="&amp;lt;code&amp;gt;create-table&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;CREATE TABLE&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;Similarly to &lt;code&gt;INSERT INTO&lt;/code&gt;, but without any expression evaluation, we
map the &lt;code&gt;CreateTableAST&lt;/code&gt; to &lt;code&gt;Storage&lt;/code&gt; entities and write them to
storage.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executeCreateTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateTableAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryResponseResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for column name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not allocate for column kind&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For both &lt;code&gt;CREATE TABLE&lt;/code&gt; and &lt;code&gt;INSERT INTO&lt;/code&gt; there is more validation we
could do. Exercise for the reader and whatnot. :)&lt;/p&gt;
&lt;h4 id="&amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;execute&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;Finally we can switch on the &lt;code&gt;AST&lt;/code&gt; and call the appropriate execution
function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QueryResponseResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;createTable&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executeCreateTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createTable&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now we're ready to put it all together in &lt;code&gt;main&lt;/code&gt;!&lt;/p&gt;
&lt;h3 id="&amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;-(&amp;lt;code&amp;gt;main.zig&amp;lt;/code&amp;gt;,-144-loc)"&gt;&lt;code&gt;main&lt;/code&gt; (&lt;code&gt;main.zig&lt;/code&gt;, 144 LoC)&lt;/h3&gt;&lt;p&gt;First we set up our arena allocator.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;std&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rocksdb.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;lex.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;parse.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;execute.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;storage.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arena&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArenaAllocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page_allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arena&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deinit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arena&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we parse CLI arguments. Importantly we need to grab a location on
disk for RocksDB to store data. And we need a query to execute.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debugTokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;debugAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scriptArg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;databaseArg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--debug-tokens&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;debugTokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--debug-ast&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;debugAST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--database&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;databaseArg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--script&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;scriptArg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;databaseArg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--database is a required flag. Should be a directory for data.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scriptArg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--script is a required flag. Should be a file containing SQL.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we read the file passed for the query.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;openFileZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;scriptArg&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getEndPos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And pass the query to the lexer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexErr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lexErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to lex: {s}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debugTokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Token: {s}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Program is empty&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pass the tokens to the parser.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to parse: {s}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debugAST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Initialize storage.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dataDirectory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;databaseArg&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dataDirectory&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to open database: {s}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And execute and print results. :)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to execute: {s}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ok&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;| &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{s}&lt;/span&gt;&lt;span class="se"&gt;\t\t&lt;/span&gt;&lt;span class="s"&gt;|&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;+ &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fieldLen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fieldLen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;fieldLen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\t\t&lt;/span&gt;&lt;span class="s"&gt;+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;| &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{s}&lt;/span&gt;&lt;span class="se"&gt;\t\t&lt;/span&gt;&lt;span class="s"&gt;|&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="build.zig"&gt;build.zig&lt;/h3&gt;&lt;p&gt;Finally, finally, tie it all together with &lt;code&gt;build.zig&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;builtin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;zig_version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;std&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addExecutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linkLibC&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linkSystemLibraryName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rocksdb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;@hasDecl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;@TypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;addLibraryPath&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLibraryPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./rocksdb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addIncludePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./rocksdb/include&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLibPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./rocksdb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addIncludeDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./rocksdb/include&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setOutputDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isDarwin&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addRPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Grab RocksDB, build it, and build our CLI.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://github.com/facebook/rocksdb
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rocksdb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;shared_lib&lt;span class="w"&gt; &lt;/span&gt;-j8&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ONLY IF YOU ARE ON A MAC&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;rocksdb/*.dylib&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# ONLY IF YOU ARE ON A MAC&lt;/span&gt;
&lt;span class="c1"&gt;# DONE ONLY IF YOU ARE ON A MAC&lt;/span&gt;

$&lt;span class="w"&gt; &lt;/span&gt;zig&lt;span class="w"&gt; &lt;/span&gt;build
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And give it a go. :)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;--database&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;--script&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;CREATE TABLE y (year int, age int, name text)&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;CREATE TABLE y (year int, age int, name text)&amp;quot;&lt;/span&gt;
ok
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;--database&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;--script&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INSERT INTO y VALUES (2010, 38, 'Gary')&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INSERT INTO y VALUES (2010, 38, 'Gary')&amp;quot;&lt;/span&gt;
ok
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;--database&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;--script&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INSERT INTO y VALUES (2021, 92, 'Teej')&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INSERT INTO y VALUES (2021, 92, 'Teej')&amp;quot;&lt;/span&gt;
ok
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;--database&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;--script&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INSERT INTO y VALUES (1994, 18, 'Mel')&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INSERT INTO y VALUES (1994, 18, 'Mel')&amp;quot;&lt;/span&gt;
ok

&lt;span class="c1"&gt;# Basic query&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;--database&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;--script&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SELECT name, age, year FROM y&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SELECT name, age, year FROM y&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;age&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;year&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;
+&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;====&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;+&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;+&lt;span class="o"&gt;====&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;+
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Mel&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;1994&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Gary&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;38&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;2010&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Teej&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;92&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;2021&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;

&lt;span class="c1"&gt;# With WHERE&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;--database&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;--script&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SELECT name, year, age FROM y WHERE age &amp;lt; 40&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SELECT name, year, age FROM y WHERE age &amp;lt; 40&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;year&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;age&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;
+&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;====&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;+&lt;span class="o"&gt;====&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;+&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;+
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Mel&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;1994&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Gary&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;2010&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;38&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;

&lt;span class="c1"&gt;# With operations&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;--database&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;--script&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SELECT 'Name: ' || name, year + 30, age FROM y WHERE age &amp;lt; 40&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SELECT 'Name: ' || name, year + 30, age FROM y WHERE age &amp;lt; 40&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;unknown&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;unknown&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;age&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;
+&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=======&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;+&lt;span class="o"&gt;=======&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;+&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;+
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Name:&lt;span class="w"&gt; &lt;/span&gt;Mel&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;2024&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Name:&lt;span class="w"&gt; &lt;/span&gt;Gary&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;2040&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="m"&gt;38&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="from-here"&gt;From Here&lt;/h3&gt;&lt;p&gt;As mentioned, this project is a vast simplification and there are
plenty of bugs and subpar design choices. But hopefully it helps to
make database development feel a little less intimidating!&lt;/p&gt;
&lt;p&gt;If you liked this, here are some other things you might want to check
out!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/23463279-designing-data-intensive-applications"&gt;Designing Database Intensive Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/en/book/show/44647144-database-internals"&gt;Database Internals: A Deep Dive Into How Distributed Data Systems Work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reddit.com/r/databasedevelopment"&gt;r/databasedevelopment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eatonphil.com/discord.html"&gt;The #dbs channel on a software internals/hacking Discord I run&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gosql"&gt;gosql&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And of course, other posts on this blog. :)&lt;/p&gt;
&lt;p&gt;Lastly, a few resources that helped me out while hacking on this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ziglang.org/documentation/master/"&gt;Zig Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Browsing the source code (and tests!!) of standard library data structures&lt;/li&gt;
&lt;li&gt;&lt;a href="https://discord.gg/gxsFFjE"&gt;Zig Programming Language Discord's #zig-help channel&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;Friendly and helpful crowd :)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Spent a month hacking on it and happy to finally have this post out.&lt;br /&gt;&lt;br /&gt;Let's build a basic SQL database in Zig on top of RocksDB. 😃&lt;a href="https://t.co/fkSnaEKsya"&gt;https://t.co/fkSnaEKsya&lt;/a&gt; &lt;a href="https://t.co/adfpMvvvOn"&gt;pic.twitter.com/adfpMvvvOn&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1591974393130934273?ref_src=twsrc%5Etfw"&gt;November 14, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 13 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/zigrocks-sql.html</guid></item><item><title>Blackbird: A reference architecture for local-first connected mobile apps</title><link>https://blog.metaobject.com/2022/06/blackbird-simple-reference-architecture.html</link><description>Wow, what a mouthful!  Although this architecture has featured in a number of my other writings,
I haven't really described it in detail by itself.  Which is a shame, because I think it 
works really well and is quite simple, a case of &lt;a href="https://blog.metaobject.com/2014/04/sophisticated-simplicity.html"&gt;Sophisticated Simplicity&lt;/a&gt;.&lt;p&gt;

&lt;h3&gt;Why a reference architecture?&lt;/h3&gt;

The motivation for creating and now presenting this reference architecture is that the way we
build connected mobile apps is broken, and none of the proposed solutions appear to help.
How are they broken?  They are
overly complex, require way too much code, perform poorly and are unreliable.&lt;p&gt;

Very broadly speaking, these problems can be traced to the misuse of procedural abstraction for
a problem-space that is broadly state-based, and can be solved by adapting a state-based 
architectural style such as in-process REST and combining it with well-known styles such
as MVC.&lt;p&gt;

More specifically, MVC has been misapplied by combining UI updates with the model updates, a
practice that becomes especially egregious with asynchronous call-backs. In addition, data
is pushed to the UI, rather than having the UI pull data when and as needed.
Asynchronous code is modelled using call/return and call-backs, leading to call-back hell, 
needless and arduous transformation of any dependent code into asynchronous code (see "what
color is your function") that is also much harder to read, discouraging appropriate
abstractions.&lt;p&gt;

Backend communication is also an issue, with newer async/await implementations not really
being much of an improvement over callback-based ones, and arguably worse in
terms of actual readability.  (They seem readable, but what actually happens is different 
enough that the simplicity is deceptive).



&lt;h3&gt;Overview&lt;/h3&gt;

The overall architecture has four fundamental components:  

&lt;ol&gt;
&lt;li&gt;The model&lt;/li&gt;
&lt;li&gt;The UI&lt;/li&gt;
&lt;li&gt;The backend&lt;/li&gt;
&lt;li&gt;The persistence&lt;/li&gt;
&lt;/ol&gt;

The main objective of the architecture is to keep these components in sync with each other, so the whole
thing somewhat resembles a control loop architecture:  something disturbs the system, for example
the user did something in the UI, and the system responds by re-establishing equilibrium.&lt;p&gt;

The model is the central component, it connects/coordinates all the pieces and is also the only one directly
connected to more than one piece.  In keeping with hexagonal architecture, the model is also supposed to
be the only place with significant logic, the remainder of the system should be as minimal, transparent
and dumb as possible.&lt;p&gt;

&lt;pre&gt;
memory-model := persistence.
persistence  |= memory-model.
ui          =|= memory-model. 
backend     =|= memory-model.

&lt;/pre&gt;

Graphically:&lt;br /&gt;

&lt;img height="250" src="https://www.dropbox.com/s/lsxucl6m5rn7q9c/overall-arch.png?raw=1" /&gt;





&lt;h3&gt;Elements&lt;/h3&gt;

Blackbird depends crucially on a number of architectural elements:  first are &lt;em&gt;stores&lt;/em&gt;
of the in-process REST architectural style.  These can be thought of as in-process HTTP servers
(without the HTTP, of course) or composable dictionaries.  The core store protocol implements
the GET, PUT and DELETE verbs as messages.&lt;p&gt;

The role of URLs in REST is taken by Polymorphic Identifiers.  These are objects that can
reference identify values in the store, but are not direct pointers.  For example, they 
need to be a able to reference objects that aren't there yet.&lt;p&gt;

Polymorphic Identifiers can be application-specific, for example they might consist 
just of a numeric id, 


&lt;h3&gt;MVC&lt;/h3&gt;

For me, the key part of the MVC architectural style is the decoupling of input processing
and resultant output processing.  That is, under MVC, the view (or a controller) make 
some change to the model and then processing stops.  At some undefined later time
(could be synchronous, but does not have to be) the Model informs the UI that it
has changed using some kind of notification mechanism.&lt;p&gt;


In Smalltalk MVC, this is a 
dependents list maintained in the model that interested views register with.  All
these views are then sent a &lt;code&gt;#changed&lt;/code&gt; message when the model has changed.
In Cocoa, this can be accomplished using &lt;code&gt;NSNotificationCenter&lt;/code&gt;, but really
any kind of broadcast mechanism will do.&lt;p&gt;

It is then the views' responsibility to update themselves by interrogating the model.&lt;p&gt;
For views, Cocoa largely automates this: on receipt of the notification, the view just
needs invalidate itself, the system then automatically schedules it for redrawing the
next time through the event loop.&lt;p&gt;

The reason the decoupling is important to maintain is that the update
notification can come for any other reason, including a different user interaction,
a backend request completing or even some sort of notification or push event
coming in remotely.&lt;p&gt;

With the decoupled M-V update mechanism, all these different
kinds of events are handled identically, and thus the UI only ever needs to deal with
the local model.  The UI is therefore almost entirely decoupled from network
communications, we thus have a local-first application that is also largely
testable locally.&lt;p&gt;


Blackbird refines the MVC view update mechanism by adding the polymorphic identifier
of the modified item in question and placing those PIs in a queue.  The queue 
decouples model and view even more than in the basic MVC model, for example it
become fairly trivial to make the queue writable from any thread, but empty only
onto the main thread for view updates.  In addition, providing update notifications
is no longer synchronous, the updater just writes an entry into the queue and can
then continue, it doesn't wait for the UI to finish its update.&lt;p&gt;

Decoupling via a queue in this way is almost sufficient for making sure that 
high-speed model updates don't overwhelm the UI or slow down the model. Both
these performance problems are fairly rampant, as an example of the first,
the Microsoft Office installer saturates both CPUs on a dual core machine 
just painting its progress bar, because it massively overdraws.&lt;p&gt;

An example of the second was one of the real performance puzzlers of my 
career:  an installer that was extremely slow, despite both CPU and disk
being mostly idle.  The problem turned out to be that the developers of
that installer not only insisted on displaying every single file name 
the installer was writing (bad enough), but also flushing the window to
screen to make sure the user got a chance to see it (worse).  This then
interacted with a behavior of Apple's CoreGraphics, which disallows 
screen flushes at a rate greater than the screen refresh rate, and will
simply throttle such requests.  You really want to decouple your UI
from your model updates and let the UI process updates at its pace.&lt;p&gt;

Having polymorphic identifiers in the queue makes it possible for the UI
to catch up on its own terms, and also to remove updates that are no longer
relevant, for example discarding duplicate updates of the same element.&lt;p&gt;

The polymorphic identifier can also be used by views in order to determine
whether they need to update themselves, by matching against the polymorphic
identifier they are currently handling.&lt;p&gt;


&lt;h3&gt;Backend communication&lt;/h3&gt;

Almost every REST backend communication code I have seen in mobile applications has
created "convenient" cover methods for every operation of every endpoint 
accessed by the application, possibly automatically generated.&lt;p&gt;

This ignores the fact that REST only has a few verbs, combined with a great number
of identifiers (URLs).  In Blackbird, there is a single channel for backend communication:
a queue that takes a polymorphic identifier and an http verb.  The polymorphic 
identifier is translated to a URL of the target backend system, the resulting request 
executed and when the result returns it is placed in the central store using the provided 
polymorphic identifier.&lt;p&gt;

After the item has been stored, an MVC notification with the polymorphic identifier in
question is enqueued as per above.&lt;p&gt;

The queue for backend operations is essentially the same one we described for model-view
communication above, for example also with the ability to deduplicate requests correctly
so only the final version of an object gets sent if there are multiple updates.  The remainder
of the processing is performed in pipes-and-filters architectural style using polymorphic
write streams.&lt;p&gt;

If the backend needs to communicate with the client, it can send URLs via a socket or
other mechanism that tells the client to pull that data via its normal request channels,
implementing the same pull-constraint as in the rest of the system.&lt;p&gt;

One aspect of this part of the architecture is that backend requests are reified and
explicit, rather than implicitly encoded on the call-stack and its potentially
asynchronous continuations.  This means it is straightforward for the UI to give the
user appropriate feedback for communication failures on the slow or disrupted network
connections that are the norm on mobile networks, as well as avoid accidental duplicate
requests.&lt;p&gt;

Despite this extra visibility and introspection, the code required to implement backend
communications is drastically reduced.  Last not least, the code is isolated:  network code
can operate independently of the UI just as well as the UI can operate
independently of the network code.&lt;p&gt;

&lt;h3&gt;Persistence&lt;/h3&gt;


Persistence is handled by stacked stores (storage combinators). &lt;p&gt;

 
&lt;img height="250" src="https://www.dropbox.com/s/8go76u12du9e5if/disk-cache-json-aligned.png?raw=1" /&gt;

&lt;p&gt;
The application is hooked up to the top of the storage stack, the CachingStore, which looks
to the application exactly like the DictStore (an in-memory store).  If a read request cannot
be found in the cache, the data is instead read from disk, converted from JSON by a mapping 
store.&lt;p&gt;

For testing the rest of the app (rather than the storage stack), it is perfectly fine to 
just use the in-memory store instead of the disk store, as it has the same interface and
behaves the same, except being faster and non-persistent.&lt;p&gt;

Writes use the same asynchronous queues as the rest of the system, with the writer getting
the polymorphic identifiers of objects to write and then retrieving the relevant object(s)
from the in-memory store before persisting.  Since they use the same mechanism, they also
benefit from the same uniquing properties, so when the I/O subsystem gets overloaded it
will adapt by dropping redundant writes.&lt;p&gt;

&lt;img height="400" src="https://www.dropbox.com/s/h2kq2joy20lmy7f/async-writer.png?raw=1" /&gt;

&lt;p&gt;


&lt;h3&gt;Consequences&lt;/h3&gt;

With the Blackbird reference architecture, we not only replace complex, bulky code with much
less and much simpler code, we also get to reuse that same code in all parts of the system
while making the pieces of the system highly independent of each other and optimising 
performance.&lt;p&gt;

In addition, the combination of REST-like stores that can be composed with constraint- and event-based
communication patterns makes the architecture highly decoupled.  In essence it allows the 
kind of decoupling we see in well-implemented microservices architectures, but on mobile
apps without having to run multiple processes (which is often not allowed).&lt;p&gt;&lt;</description><author>metablog</author><pubDate>Sat, 12 Nov 2022 11:51:45 GMT</pubDate><guid isPermaLink="true">https://blog.metaobject.com/2022/06/blackbird-simple-reference-architecture.html</guid></item><item><title>The World Is Run By People No Smarter Than You</title><link>https://www.swyx.io/no-smarter</link><description>&lt;p&gt;This post was written as a reflection at the first Dev Writers Retreat. It's been really weird doing this in the PermaParty city while the world seemingly falls apart outside. Here's my attempt to make sense of it.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Fri, 11 Nov 2022 17:38:07 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/no-smarter</guid></item><item><title>Vim tip 17: setting options</title><link>https://learnbyexample.github.io/tips/vim-tip-17/</link><description>&lt;p&gt;From &lt;a href="https://vimhelp.org/options.txt.html"&gt;:h options.txt&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vim has a number of internal variables and switches which can be set to achieve special effects. These options come in three forms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;boolean&lt;/strong&gt; can only be on or off&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;number&lt;/strong&gt;  has a numeric value&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;string&lt;/strong&gt;  has a string value&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here are examples for each of these forms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:set cursorline&lt;/kbd&gt; highlight the line containing the cursor&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:set history=200&lt;/kbd&gt; increase default history from 50 to 200&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:set ww+=[,]&lt;/kbd&gt; allow left and right arrow keys to move across lines in Insert mode
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;+=&lt;/code&gt; allows you to append to an existing string value&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Usage guidelines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;set {option}&lt;/code&gt; switch on the given boolean setting
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:set expandtab&lt;/kbd&gt; use spaces for tab expansion&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set {option}!&lt;/code&gt; toggle the given boolean setting
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:set expandtab!&lt;/kbd&gt; if previously tabs were expanded, it will be turned off and vice versa&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set inv{option}&lt;/code&gt; can also be used&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set no{option}&lt;/code&gt; switch off the given boolean setting
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:set noexpandtab&lt;/kbd&gt; disable expanding tab to spaces&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set {option}?&lt;/code&gt; get the current value of the given option (works for all three forms)
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:set expandtab?&lt;/kbd&gt; output will be &lt;code&gt;expandtab&lt;/code&gt; or &lt;code&gt;noexpandtab&lt;/code&gt; depending on whether it is switched on or off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set {option}&lt;/code&gt; get the current value of number or string option
&lt;ul&gt;
&lt;li&gt;for example, try &lt;kbd&gt;:set history&lt;/kbd&gt; or &lt;kbd&gt;:set ww&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/options.txt.html"&gt;:h options.txt&lt;/a&gt; for complete list of usage guidelines and available options.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 08 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-17/</guid></item><item><title>The best ideas come AFK</title><link>https://www.marginalia.nu/log/67-best-ideas-afk/</link><description>&lt;p&gt;I get my best ideas when I&amp;rsquo;m not working.&lt;/p&gt;
&lt;p&gt;This seems paradoxical, but past a point, the more I work on a project the slower it seems to go. I&amp;rsquo;ll find changes to do, but lose any sort of vision.&lt;/p&gt;
&lt;p&gt;If I&amp;rsquo;m not programming at all, I rarely get good ideas as well.&lt;/p&gt;
&lt;p&gt;There appears to be some magic stoichiometric mixture where I work on a project for a while, then force myself to take a break somewhere far away from any keyword for a day or two, the ideas start to roll in at a pace where I can barely keep up to write them down.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Mon, 07 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/67-best-ideas-afk/</guid></item><item><title>Elite speak GUID script</title><link>https://boyter.org/posts/leet-speak-guid-script/</link><description>&lt;p&gt;Some time ago I wrote about creating leet speak guid&amp;rsquo;s as a way of having fun while working with sitecore. &lt;a href="https://boyter.org/2014/05/unique-guid/"&gt;https://boyter.org/2014/05/unique-guid/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I recently realised I wanted to have this around so I could create more interesting guids for one reason or another, but couldn&amp;rsquo;t find the script I was using back then. So I created it again, and its now on github as a gist for myself and anyone else to use &lt;a href="https://gist.github.com/boyter/6f5b7c1b375e79449d01916f5828e1db"&gt;https://gist.github.com/boyter/6f5b7c1b375e79449d01916f5828e1db&lt;/a&gt; feel free to use it as you wish!&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Mon, 07 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/leet-speak-guid-script/</guid></item><item><title>Github Not-So-Reusable Actions</title><link>https://smcleod.net/2022/11/github-not-so-reusable-actions/</link><description>Github Actions Reusable Workflows vs Composite Actions</description><author>smcleod.net</author><pubDate>Sun, 06 Nov 2022 06:52:27 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/11/github-not-so-reusable-actions/</guid></item><item><title>YAML Anchors and Aliases</title><link>https://smcleod.net/2022/11/yaml-anchors-and-aliases/</link><description>Using YAML Anchors and Aliases to make config files more DRY</description><author>smcleod.net</author><pubDate>Sun, 06 Nov 2022 06:52:27 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/11/yaml-anchors-and-aliases/</guid></item><item><title>Zsh Configuration and Plugins - Part One</title><link>https://smcleod.net/2022/11/zsh-configuration-and-plugins-part-one/</link><description>My Z-Shell configuration, scripts and hacks</description><author>smcleod.net</author><pubDate>Sun, 06 Nov 2022 01:32:43 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/11/zsh-configuration-and-plugins-part-one/</guid></item><item><title>Return to Blizzard</title><link>https://benovermyer.com/blog/2022/11/return-to-blizzard/</link><description>&lt;p&gt;A few weeks ago, I made the decision to rescind my ban on playing Blizzard games. In part this was because Overwatch 2 was imminent, and I missed the particular style of gameplay that only Overwatch had. But it was also because I know people who work at Blizzard, and boycotting Blizzard games appears to be wholly ineffective at assisting change.&lt;/p&gt;
&lt;p&gt;This unlocking of the gate meant several things. I could play Overwatch 1 for one more day before the launch of the "sequel." Overwatch 2 completely replaced the original game, so the first one is gone now. I also needed to preorder the collector's edition of the next WoW expansion if I could. I own every expansion collector's edition - though not the CE for the original game, sadly. That, to my surprise, I accomplished easily by ordering through Blizzard's online store. I wonder if demand is down further than I expected. Finally, I installed the Diablo 2 remake and played it for several hours. I had preordered it prior to my ban, but the ban went into effect before its release.&lt;/p&gt;
&lt;p&gt;Now, I've played Overwatch 2 for many hours, and I'm levelling my main in WoW to get ready for the release of the Dragonflight expansion later this month. I have until November 15 to reach level 60, and I'm level 58 now. Should be doable unless I get distracted by other things.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Fri, 04 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/11/return-to-blizzard/</guid></item><item><title>CLI tip 18: inserting file contents using GNU sed</title><link>https://learnbyexample.github.io/tips/cli-tip-18/</link><description>&lt;p&gt;The &lt;code&gt;r&lt;/code&gt; command accepts a filename as argument and when the address is satisfied, entire contents of the given file is added &lt;em&gt;after&lt;/em&gt; the matching line. This is a robust way to add multiline text literally.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat ip.txt
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; sky
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; apple
&lt;/span&gt;&lt;span&gt;$ cat fav_colors.txt
&lt;/span&gt;&lt;span&gt;deep red
&lt;/span&gt;&lt;span&gt;yellow
&lt;/span&gt;&lt;span&gt;reddish
&lt;/span&gt;&lt;span&gt;brown
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# space between r and filename is optional
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# adds entire contents of 'ip.txt' after each line containing 'red'
&lt;/span&gt;&lt;span&gt;$ sed &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'/red/r ip.txt'&lt;/span&gt;&lt;span&gt; fav_colors.txt
&lt;/span&gt;&lt;span&gt;deep red
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; sky
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; apple
&lt;/span&gt;&lt;span&gt;yellow
&lt;/span&gt;&lt;span&gt;reddish
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; sky
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; apple
&lt;/span&gt;&lt;span&gt;brown
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;e&lt;/code&gt; flag is the easiest way to insert file contents &lt;em&gt;before&lt;/em&gt; the matching lines. Similar to the &lt;code&gt;r&lt;/code&gt; command, the output of an external command (&lt;code&gt;cat&lt;/code&gt; in the below example) is inserted literally.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ sed &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'/red/e cat ip.txt'&lt;/span&gt;&lt;span&gt; fav_colors.txt
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; sky
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; apple
&lt;/span&gt;&lt;span&gt;deep red
&lt;/span&gt;&lt;span&gt;yellow
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; sky
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt; apple
&lt;/span&gt;&lt;span&gt;reddish
&lt;/span&gt;&lt;span&gt;brown
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://learnbyexample.github.io/learn_gnused/adding-content-from-file.html"&gt;Adding content from file&lt;/a&gt; chapter from my &lt;strong&gt;GNU sed&lt;/strong&gt; ebook for many more examples, gotchas, details about the &lt;code&gt;R&lt;/code&gt; command and so on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/learn_gnused"&gt;CLI text processing with GNU sed&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 02 Nov 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-18/</guid></item><item><title>How to add Tailwind 3 to Docusaurus 2 in 2022</title><link>https://www.swyx.io/tailwind-docusaurus-2022</link><description>&lt;p&gt;We use Docusaurus at work, and while it shipped v2 this year it still has (&lt;a href="https://github.com/facebook/docusaurus/issues/2961"&gt;as of v2.3&lt;/a&gt;) not shipped with any Tailwind support at all. Googled and found &lt;a href="https://dev.to/sajclarke_62/using-tailwindcss-v3-in-docusaurus-in-5-steps-5c26"&gt;this post&lt;/a&gt; which was almost everything I needed, but required some stuff in the comments for it to work.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Tue, 01 Nov 2022 04:35:34 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/tailwind-docusaurus-2022</guid></item><item><title>Encourage Your Peers To Contribute To Open Source</title><link>https://smcleod.net/2022/10/encourage-your-peers-to-contribute-to-open-source/</link><description>&lt;p&gt;Contributing to Open Source is important to the quality and maintainability of the software and engineering communities we rely on every day - so why is it that so many developers/engineers never participate?&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Sun, 30 Oct 2022 09:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/10/encourage-your-peers-to-contribute-to-open-source/</guid></item><item><title>A minimal RocksDB example with Zig</title><link>http://notes.eatonphil.com/zigrocks.html</link><description>&lt;p&gt;I mostly programmed in Go the last few years. So every time I
wanted an embedded key-value database, I reached for Cockroach's
&lt;a href="https://github.com/cockroachdb/pebble"&gt;Pebble&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pebble is great for Go programming but Go does not embed well into
other languages. Pebble was inspired by
&lt;a href="https://github.com/facebook/rocksdb"&gt;RocksDB&lt;/a&gt; (and its predecessor,
&lt;a href="https://github.com/google/leveldb"&gt;LevelDB&lt;/a&gt;). Both were written in
C++ which can more easily be embedded into any language with a C
foreign function interface. Pebble also has some interesting
limitations that RocksDB does not,
&lt;a href="https://github.com/facebook/rocksdb/wiki/Transactions"&gt;transactions&lt;/a&gt;
for example.&lt;/p&gt;
&lt;p&gt;So I've been wanting to get familiar with RocksDB. And I've been
learning Zig, so I set out to write a simple Zig program that embeds
RocksDB.  (If you see weird things in my Zig code and have
suggestions, &lt;a href="mailto:phil@eatonphil.com"&gt;send me a note&lt;/a&gt;!)&lt;/p&gt;
&lt;p&gt;This post is going to be a mix of RocksDB explanations and Zig
explanations. By the end we'll have a simple CLI over a durable store
that is able to set keys, get keys, and list all key-value pairs
(optionally filtered on a key prefix).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./kv&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./kv&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;x
&lt;span class="m"&gt;1&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./kv&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;22&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./kv&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;x
&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./kv&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;y
&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;22&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./kv&lt;span class="w"&gt; &lt;/span&gt;list
&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;22&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Basic stuff!&lt;/p&gt;
&lt;p&gt;You can find the code for this post in the &lt;a href="https://github.com/eatonphil/zigrocks"&gt;rocksdb.zig file on
Github&lt;/a&gt;. To simplify things,
this code is only going to work on Linux. And it will require Zig
0.10.x.&lt;/p&gt;
&lt;h3 id="rocksdb"&gt;RocksDB&lt;/h3&gt;&lt;p&gt;RocksDB is written in C++. But most languages cannot interface with
C++. (Zig cannot either, as far as I understand). So most C++
libraries expose a C API that is easier for other programming
languages to interact with. RocksDB does this. Great!&lt;/p&gt;
&lt;p&gt;Now RocksDB's &lt;a href="https://github.com/facebook/rocksdb/wiki"&gt;C++
documentation&lt;/a&gt; is
phenomenal, especially among C++ libraries. But if there is
documentation for the C API, I couldn't find it. Instead you must
trawl through the &lt;a href="https://github.com/facebook/rocksdb/blob/main/include/rocksdb/c.h"&gt;C header
file&lt;/a&gt;,
the &lt;a href="https://github.com/facebook/rocksdb/blob/main/db/c.cc"&gt;C wrapper
implementation&lt;/a&gt;,
and the &lt;a href="https://github.com/facebook/rocksdb/blob/main/db/c_test.c"&gt;C
tests&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There was also a &lt;a href="https://gist.github.com/nitingupta910/4640638be7e7ad39c41e"&gt;great gist showing a minimal RocksDB C
example&lt;/a&gt;. But
it didn't cover the iterator API for fetching a range of keys with a
prefix. But with the C tests file I was able to figure it out, I
think.&lt;/p&gt;
&lt;p&gt;Let's dig in!&lt;/p&gt;
&lt;h3 id="creating,-opening-and-closing-a-rocksdb-database"&gt;Creating, opening and closing a RocksDB database&lt;/h3&gt;&lt;p&gt;First we need to import the C header so that Zig can compile-time
verify the foreign functions we call. We'll also import the standard
library that we'll use later.&lt;/p&gt;
&lt;p&gt;Aside from &lt;code&gt;build.zig&lt;/code&gt; below, all code should be in &lt;code&gt;main.zig&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;std&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@cImport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;@cInclude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rocksdb/c.h&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  Don't read anything into the `@` other than that this is a compiler
  builtin. It's used for imports, casting, and other metaprogramming.
&lt;/p&gt;&lt;p&gt;Now we can build our wrapper. It will be a Zig struct that contains a
pointer to the RocksDB instance.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To open a database we'll call &lt;code&gt;rocksdb_open()&lt;/code&gt; with a directory name
for RocksDB to store data. And we'll tell RocksDB to create the
database if it doesn't already exist.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?*&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_options_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_options_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_options_set_create_if_missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?*&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we close with &lt;code&gt;rocksdb_close()&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The RocksDB aspect of this is easy. But there's a bunch of
Zig-specific details I should (try to) explain.&lt;/p&gt;
&lt;h4 id="return-types"&gt;Return types&lt;/h4&gt;&lt;p&gt;Zig has a cool
&lt;a href="https://ziglang.org/documentation/master/#Errors"&gt;&lt;code&gt;error&lt;/code&gt;&lt;/a&gt;
type. &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; in Zig work only with this &lt;code&gt;error&lt;/code&gt; type and
subsets of it you can create. &lt;code&gt;error&lt;/code&gt; is an enum. But Zig &lt;code&gt;error&lt;/code&gt;s are not
ML-style tagged unions (yet?). That is, you cannot both return an
error and some dynamic information about the error. So the usefulness
of &lt;code&gt;error&lt;/code&gt; is limited. It mostly only works if the errors are a finite
set without dynamic aspects.&lt;/p&gt;
&lt;p&gt;Zig also doesn't have multiple return values. But it does have
optional types (denoted with &lt;code&gt;?&lt;/code&gt;) and it has anonymous structs.&lt;/p&gt;
&lt;p&gt;So we can do a slightly less safe, but more informational, error type
by returning a struct with an optional success value and an optional
error.&lt;/p&gt;
&lt;p&gt;That's how we get the return type &lt;code&gt;struct { val: ?RocksDB, err: ?[]u8 }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is not very different from Go, certainly no less safe, and I'm
probably biased to use this as a Go programmer.&lt;/p&gt;
&lt;p class="note"&gt;
  Felix Queißner points out to me that there are tagged unions in Zig
  that would be more safe here. Instead of &lt;code&gt;struct { val:
  ?RocksDB, err: ?[]u8 }&lt;/code&gt; I could do &lt;code&gt;union(enum) { val:
  RocksDB, err: []u8 }&lt;/code&gt;. When I get a chance to play with that
  syntax I'll modify this post.
&lt;/p&gt;&lt;h4 id="optional-pointers"&gt;Optional pointers&lt;/h4&gt;&lt;p&gt;The next thing you may notice is &lt;code&gt;?*rdb.rocksdb_options_t&lt;/code&gt; and
&lt;code&gt;?*rdb.rocksdb_t&lt;/code&gt;. This is to work with Zig's type system. Zig expects
that pointers are not null. By adding &lt;code&gt;?&lt;/code&gt; we are telling Zig that this
value can be null. That way the Zig type system will force us to
handle the null condition if we try to access fields on the value.&lt;/p&gt;
&lt;p&gt;In the options case, it doesn't really matter if the result is &lt;code&gt;null&lt;/code&gt;
or not. In the database case, we handle null-ness it by checking the
error value &lt;code&gt;if (err) |errStr|&lt;/code&gt;. If this condition is &lt;em&gt;not&lt;/em&gt; met, we
know the database is not null. So we use &lt;code&gt;db.?&lt;/code&gt; to assert and return a
value that, in the type system, is not null.&lt;/p&gt;
&lt;h4 id="zig-strings,-c-strings"&gt;Zig strings, C strings&lt;/h4&gt;&lt;p&gt;Another thing you may notice is &lt;code&gt;var err:
?[*:0]u8 = null;&lt;/code&gt;. Zig strings are expressed as byte arrays or byte
slices. &lt;code&gt;[]u8&lt;/code&gt; and &lt;code&gt;[]const u8&lt;/code&gt; are slices that keep track of the
number of items. &lt;code&gt;[*:0]u8&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a byte slice. It has no length and
is only null-delimited. To go from the null-delimited array that the C
API returns to the &lt;code&gt;[]u8&lt;/code&gt; (slice that contains length) in our
function's return signature we use
&lt;a href="https://github.com/ziglang/zig/blob/30b8b29f88362d18ea6523a859b29f7bc6dec622/lib/std/mem.zig"&gt;&lt;code&gt;std.mem.span&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/72736997/how-to-pass-a-c-string-into-a-zig-function-expecting-a-zig-string"&gt;This StackOverflow
post&lt;/a&gt;
was useful for understanding this.&lt;/p&gt;
&lt;h4 id="structs"&gt;Structs&lt;/h4&gt;&lt;p&gt;Anonymous structs in Zig are prefixed with a &lt;code&gt;.&lt;/code&gt;. And all struct
fields, anonymous or not, are prefixed with &lt;code&gt;.&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;.{.x = 1}&lt;/code&gt; instantiates an anonymous struct that has one field
&lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Struct fields in Zig cannot &lt;em&gt;not&lt;/em&gt; be instantiated, even if they are
nullable. And when you initialize a nullable value you don't need to
wrap it in a &lt;code&gt;Some()&lt;/code&gt; like you might do in an ML.&lt;/p&gt;
&lt;p&gt;One thing I found surprising about Zig anonymous structs is that
instances of the anonymous &lt;em&gt;type&lt;/em&gt; are created per function and two
anonymous structs that are structurally identical but referenced in
different functions are not actually type-equal.&lt;/p&gt;
&lt;p&gt;So this doesn't compile:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doA&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;
&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doB__struct_2890&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doA__struct_3878&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doA&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;~~~^~&lt;/span&gt;
&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;declared&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;^~~~~~~~~~~~~~~~&lt;/span&gt;
&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;declared&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;^~~~~~~~~~~~~~~~&lt;/span&gt;
&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;declared&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;^~~~~~~~~~~~~~~~&lt;/span&gt;
&lt;span class="n"&gt;referenced&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;callMain&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;whatever&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;606&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;freference&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;see&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traces&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You would need to instantiate a new anonymous struct in the second function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doA&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="uniform-function-call-syntax"&gt;Uniform function call syntax&lt;/h4&gt;&lt;p&gt;Zig seems to support something like &lt;a href="https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax"&gt;uniform function call
syntax&lt;/a&gt;
where you can either call a function with arguments or you can omit
the first argument by prefixing the function call with
&lt;code&gt;firstargument.&lt;/code&gt;. I.e. &lt;code&gt;x.add(y)&lt;/code&gt; and &lt;code&gt;add(x, y)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the case of this code it would be &lt;code&gt;RocksDB.close(db)&lt;/code&gt; vs
&lt;code&gt;db.close()&lt;/code&gt; assuming &lt;code&gt;db&lt;/code&gt; is an instance of the &lt;code&gt;RocksDB&lt;/code&gt; struct.&lt;/p&gt;
&lt;p&gt;Like Python, the use of &lt;code&gt;self&lt;/code&gt; as the name of this first parameter of
a struct's methods is purely convention. You can call it whatever.&lt;/p&gt;
&lt;p&gt;The point is that we always expect the user to &lt;code&gt;var db = RocksDB.open()&lt;/code&gt; for
&lt;code&gt;open()&lt;/code&gt; and allow the user to do &lt;code&gt;db.close()&lt;/code&gt; for &lt;code&gt;close()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let's move on!&lt;/p&gt;
&lt;h3 id="setting-a-key-value-pair"&gt;Setting a key-value pair&lt;/h3&gt;&lt;p&gt;We set a pair by calling &lt;code&gt;rocksdb_put&lt;/code&gt; with the database instance,
some options (we'll leave to defaults), and the key and value strings
as C strings.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;writeOptions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_writeoptions_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;writeOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;errStr&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only special Zig thing is there is &lt;code&gt;key.ptr&lt;/code&gt; to satisfy the Zig /
C type system. The type signature &lt;code&gt;key: [:0]const u8&lt;/code&gt; and &lt;code&gt;value:
[:0]const u8&lt;/code&gt; makes sure that the user passes in a null-delimited
byte slice, which is what the RocksDB API expects.&lt;/p&gt;
&lt;h3 id="getting-a-value-from-a-key"&gt;Getting a value from a key&lt;/h3&gt;&lt;p&gt;We set a pair by calling &lt;code&gt;rocksdb_get&lt;/code&gt; with the database instance,
some options (we'll again leave to defaults), and the key as a C
string.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readOptions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_readoptions_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valueLength&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;readOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;valueLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;errStr&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;valueLength&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One thing in there to call out is that we can go from a null-delimited
value &lt;code&gt;v&lt;/code&gt; to a standard Zig slice &lt;code&gt;[]u8&lt;/code&gt; by slicing from &lt;code&gt;0&lt;/code&gt; to the
length of the value returned by the C API.&lt;/p&gt;
&lt;p&gt;Also, &lt;code&gt;rocksdb_get&lt;/code&gt; is only used for getting a single key-value
pair. We'll handle key-value pair iteration next.&lt;/p&gt;
&lt;h3 id="iterating-over-key-value-pairs"&gt;Iterating over key-value pairs&lt;/h3&gt;&lt;p&gt;The basic structure of RocksDB's iterator API is that you first create
an iterator instance with &lt;code&gt;rocksdb_create_iterator()&lt;/code&gt;. Then you either
&lt;code&gt;rocksdb_iter_seek_to_first()&lt;/code&gt; or &lt;code&gt;rocksdb_iter_seek()&lt;/code&gt; (with a
prefix) to get the iterator ready. Then you get the current iterator
entry's key with &lt;code&gt;rocksdb_iter_key()&lt;/code&gt; and value with
&lt;code&gt;rocksdb_iter_value()&lt;/code&gt;. You move on to the next entry in the iterator
with &lt;code&gt;rocksdb_iter_next()&lt;/code&gt; and check that the current iterator value
is valid with &lt;code&gt;rocksdb_iter_valid()&lt;/code&gt;. When the iterator is no longer
valid, or if you want to stop iterating early, you call
&lt;code&gt;rocksdb_iter_destroy()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But we'd like to present a Zig-only interface to users of the
&lt;code&gt;RocksDB&lt;/code&gt; Zig struct. So we'll create a &lt;code&gt;RocksDB.iter()&lt;/code&gt; function that
returns a &lt;code&gt;RocksDB.Iter&lt;/code&gt; with an &lt;code&gt;RocksDB.Iter.next()&lt;/code&gt; function that
will return an optional &lt;code&gt;RocksDB.IterEntry&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We'll start backwards with that &lt;code&gt;RocksDB.Iter&lt;/code&gt; struct.&lt;/p&gt;
&lt;h4 id="&amp;lt;code&amp;gt;rocksdb.iter&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;RocksDB.Iter&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;Each iterator instance will store a pointer to a RocksDB iterator
instance. It will store the prefix requested (which is allowed to be
an empty string). If the prefix is set though, we'll only iterate
while the iterator key has the requested prefix.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IterEntry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_iterator_t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;IterEntry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_iter_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_iter_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keySize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_iter_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;keySize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;still&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;within&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;keySize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;or&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;valueSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;usize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_iter_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;valueSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IterEntry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keySize&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valueSize&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally we'll wrap the &lt;code&gt;rocksdb_iter_destroy()&lt;/code&gt; method:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_iter_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="&amp;lt;code&amp;gt;rocksdb.iter()&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;RocksDB.iter()&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;Now we can write the function that creates the &lt;code&gt;RocksDB.Iter&lt;/code&gt;. As
previously mentioned we must first instantiate the RocksDB iterator
and then &lt;code&gt;seek&lt;/code&gt; to either the first entry if the user doesn't request
a prefix. Or if the user requests a prefix, we &lt;code&gt;seek&lt;/code&gt; until that
prefix.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readOptions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_readoptions_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_create_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readOptions&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create iterator&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_iter_seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;rdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rocksdb_iter_seek_to_first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now we're done a basic Zig wrapper for the RocksDB API!&lt;/p&gt;
&lt;h3 id="&amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;main&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;Next we write a simple command-line entrypoint that uses the RocksDB
wrapper we built. This is not the prettiest code but it gets the job
done.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;openRes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RocksDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/tmp/db&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;openRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to open: {s}.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;openRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;set&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;set&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;list&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;lst&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;argNext&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argNext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Must specify command (get, set, or list). Got: '{s}'.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;set&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setErr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error setting key: {s}.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getRes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error getting key: {s}.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{s}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Key not found.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iterRes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error getting iterator: {s}.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iterRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{s} = {s}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notably, the &lt;code&gt;main&lt;/code&gt; function must be marked &lt;code&gt;pub&lt;/code&gt;. The struct and
struct methods we wrote would need to be marked &lt;code&gt;pub&lt;/code&gt; if we wanted
them accessible from other files. But since this is a single file,
&lt;code&gt;pub&lt;/code&gt; doesn't matter. Except for &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we can get into building.&lt;/p&gt;
&lt;h3 id="building"&gt;Building&lt;/h3&gt;&lt;p&gt;First we need to compile the RocksDB library. To do this we simply
&lt;code&gt;git clone&lt;/code&gt; RocksDB and run &lt;code&gt;make shared_libs&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="compiling-rocksdb"&gt;Compiling RocksDB&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://github.com/facebook/rocksdb
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rocksdb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;shared_lib&lt;span class="w"&gt; &lt;/span&gt;-j8&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This may take a while, sorry.&lt;/p&gt;
&lt;h4 id="&amp;lt;code&amp;gt;build.zig&amp;lt;/code&amp;gt;"&gt;&lt;code&gt;build.zig&lt;/code&gt;&lt;/h4&gt;&lt;p&gt;Next we need to write a &lt;code&gt;build.zig&lt;/code&gt; script that tells Zig about this
external library. This was one of the harder parts of the process, but
building and linking against foreign libraries is almost always hard.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zig&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;builtin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;zig_version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;std&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kr"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addExecutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main.zig&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linkLibC&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linkSystemLibraryName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rocksdb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLibraryPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./rocksdb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addIncludePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./rocksdb/include&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setOutputDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Felix Queißner's &lt;a href="https://zig.news/xq/zig-build-explained-part-3-1ima"&gt;zig build
explained&lt;/a&gt; series
was quite helpful.&lt;/p&gt;
&lt;p&gt;Now we just:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;zig&lt;span class="w"&gt; &lt;/span&gt;build
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And run!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;list
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;list
&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;
&lt;span class="nv"&gt;xy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;xy
&lt;span class="m"&gt;300&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;xy
&lt;span class="nv"&gt;xy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not bad!&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I wrote a new post on using RocksDB with Zig! There weren't a lot of good examples of the C API and it was good practice for learning Zig.&lt;br /&gt;&lt;br /&gt;Also sets me up for integrating it in a (WIP) port of my toy SQL database from Go to Zig. (This time with storage!)&lt;a href="https://t.co/zquojV974G"&gt;https://t.co/zquojV974G&lt;/a&gt; &lt;a href="https://t.co/gtAsB6Wrhi"&gt;pic.twitter.com/gtAsB6Wrhi&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1586908890960117760?ref_src=twsrc%5Etfw"&gt;October 31, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 30 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/zigrocks.html</guid></item><item><title>Carbon Dating HTML</title><link>https://www.marginalia.nu/log/66-carbon-dating/</link><description>&lt;p&gt;One of the more common feature requests I&amp;rsquo;ve gotten for Marginalia Search is the ability to search by date. I&amp;rsquo;ve been a bit reluctant because this has the smell of a a surprisingly hard problem. Or rather, a surprisingly large number of easy problems.&lt;/p&gt;
&lt;p&gt;The initial hurdle we&amp;rsquo;ll encounter is that among structured data, pubDate in available in RDFa, OpenGraph, JSON+LD, and Microdata.&lt;/p&gt;
&lt;p&gt;A few examples:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;meta property="datePublished" content="2022-08-24" /&amp;gt;
&amp;lt;meta itemprop="datePublished" content="2022-08-24" /&amp;gt;
&amp;lt;meta property="article:published_time" content="2022-08-24T14:39:14Z" /&amp;gt;
&amp;lt;script type="application/ld+json"&amp;gt;
{"datePublished":"2022-08-24T14:39:14Z"}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So far not so that bad. This is at least a case where the web site tells you that here is the pub-date, the exact format of the date may vary, but this is solvable.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Thu, 27 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/66-carbon-dating/</guid></item><item><title>Contemplating Randomness</title><link>https://specbranch.com/posts/random-nums/</link><description>&lt;p&gt;I have recently been immersed in the theory and practice of random number generation while working
on &lt;a href="https://arbitrand.com"&gt;Arbitrand&lt;/a&gt;, a new high-quality true random number generation service
hosted in AWS.  Because of that, I am starting a sequence of blog posts on randomness and
random number generators.  This post is the first of the sequence, and focuses what random
number generators are and how to test them.&lt;/p&gt;
&lt;p&gt;Formally, random number generators are systems that produce a stream of bits (or numbers) with
two properties:&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Thu, 27 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/random-nums/</guid></item><item><title>Python tip 18: arbitrary number of arguments</title><link>https://learnbyexample.github.io/tips/python-tip-18/</link><description>&lt;p&gt;The &lt;code&gt;print()&lt;/code&gt; function can accept zero or more values separated by a comma. Here's how the function arguments are shown in &lt;code&gt;help(print)&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(value, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sep&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;' '&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;end&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\n&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;file&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span&gt;sys.stdout, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;flush&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;False&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are some examples with varying number of arguments passed to the &lt;code&gt;print()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'hello'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;22&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42 3.142857142857143 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can write your own functions to accept arbitrary number of arguments as well. The packing syntax is similar to &lt;a href="https://learnbyexample.github.io/tips/python-tip-14/"&gt;sequence unpacking&lt;/a&gt;. A &lt;code&gt;*&lt;/code&gt; prefix to an argument name will allow it to accept zero or more values. Such an argument will be packed as a &lt;code&gt;tuple&lt;/code&gt; data type and it should always be specified after positional arguments (if any). &lt;code&gt;args&lt;/code&gt; is often used as the variable name for this purpose. Here's an example:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="background-color: #562d56bf; color: #f8f8f8;"&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;many&lt;/span&gt;&lt;span&gt;(x, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;args):
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{x = }&lt;/span&gt;&lt;span style="color: #d07711;"&gt;; &lt;/span&gt;&lt;span&gt;{args = }&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;many&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Traceback &lt;/span&gt;&lt;span&gt;(most recent call last):
&lt;/span&gt;&lt;span&gt;  File &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;, line &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &amp;lt;&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;
&lt;/span&gt;&lt;span style="color: #a2a001;"&gt;TypeError&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;many&lt;/span&gt;&lt;span&gt;() missing &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1 &lt;/span&gt;&lt;span&gt;required positional argument: &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'x'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;many&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;; args &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;many&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'two'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;; args &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'two'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's a more practical example:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="background-color: #562d56bf; color: #f8f8f8;"&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sum_nums&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;args):
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span&gt;total &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for &lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;args:
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...         &lt;/span&gt;&lt;span&gt;total &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;+= &lt;/span&gt;&lt;span&gt;n
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;return &lt;/span&gt;&lt;span&gt;total
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sum_nums&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sum_nums&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;8&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sum_nums&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;15
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sum_nums&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span style="color: #b39f04;"&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;))
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Use &lt;code&gt;**&lt;/code&gt; prefix to accept arbitrary number of keyword arguments. See also &lt;a href="https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists"&gt;docs.python: Arbitrary Argument Lists&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 26 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-18/</guid></item><item><title>Scaling doesn't scale</title><link>https://www.marginalia.nu/log/65-scaling-doesnt-scale/</link><description>&lt;p&gt;By which I mean there are deeply problematic assumptions in the very notion of scaling: Scaling changes the rules, and scaling problems exist in both directions. If what you are doing effortlessly scales up, it almost always means it&amp;rsquo;s egregiously sub-optimal given your present needs.&lt;/p&gt;
&lt;p&gt;These assertions are all very abstract. I&amp;rsquo;ll illustrate with several examples, to try and build an intuition for scaling. You most likely already know what I&amp;rsquo;m saying is true, but you may need reminding that this is how it works.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Tue, 25 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/65-scaling-doesnt-scale/</guid></item><item><title>Functions on the Heap</title><link>https://cmdev.com/blog/2022-10-21-functionsontheheap/</link><description>The history of object-oriented programming started with a simple buf very technical and low-level idea.</description><author>The Cranky Developer on Crater Moon Development</author><pubDate>Fri, 21 Oct 2022 23:39:18 GMT</pubDate><guid isPermaLink="true">https://cmdev.com/blog/2022-10-21-functionsontheheap/</guid></item><item><title>Marginalia's Index Reaches 100,000,000 Documents</title><link>https://www.marginalia.nu/log/64-hundred-million/</link><description>&lt;p&gt;A very brief note to announce reaching a long term goal and major milestone for marginalia search.&lt;/p&gt;
&lt;p&gt;The search engine now indexes 106,857,244 documents!&lt;/p&gt;
&lt;p&gt;The previous record was a bit south of seventy million. A hundred million has been a pie-in-the-sky goal for a very long time. It&amp;rsquo;s seemed borderline impossible to index a that many documents on a PC. Turns out it&amp;rsquo;s not. It&amp;rsquo;s more than possible.&lt;/p&gt;
&lt;p&gt;Twice this may even be technically doable, but is way past the pain point of sheer logistics. It&amp;rsquo;s already a real headache to deal with this much data.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Fri, 21 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/64-hundred-million/</guid></item><item><title>Making Work Visible - Avoid DMs</title><link>https://smcleod.net/2022/10/making-work-visible-avoid-dms/</link><description>&lt;p&gt;We create more value by having conversations in public instead of behind closed doors.&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Thu, 20 Oct 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/10/making-work-visible-avoid-dms/</guid></item><item><title>The Best Of - 2022 Edition</title><link>https://smcleod.net/2022/10/the-best-of-2022-edition/</link><description>&lt;p&gt;Near the end of each year I note down a summary of the best apps I&amp;rsquo;ve enjoyed using throughout the year, here&amp;rsquo;s 2022.&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Wed, 19 Oct 2022 22:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/10/the-best-of-2022-edition/</guid></item><item><title>Vim tip 16: terminal mode</title><link>https://learnbyexample.github.io/tips/vim-tip-16/</link><description>&lt;p&gt;Terminal mode is one way to use shell commands from within Vim.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:terminal&lt;/kbd&gt; open a new terminal window as a horizontal split
&lt;ul&gt;
&lt;li&gt;opens above the current window unless &lt;code&gt;splitbelow&lt;/code&gt; option is set&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:vertical :terminal&lt;/kbd&gt; open a new terminal window as a vertical split
&lt;ul&gt;
&lt;li&gt;opens to the left of the current window unless &lt;code&gt;splitright&lt;/code&gt; option is set&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are some shortcuts to navigate between windows and change modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;kbd&gt;w&lt;/kbd&gt; or &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; move to the next window
&lt;ul&gt;
&lt;li&gt;helps you to easily switch back and forth if you have one text editing window and one terminal window&lt;/li&gt;
&lt;li&gt;see the &lt;a href="https://learnbyexample.github.io/tips/vim-tip-14/"&gt;Splitting&lt;/a&gt; tip for more such commands&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;kbd&gt;N&lt;/kbd&gt; goes to Terminal-Normal mode which will help you to move around using Normal mode commands, copy text, etc (note that you need to use uppercase &lt;code&gt;N&lt;/code&gt; here)
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;\&lt;/kbd&gt; followed by &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;n&lt;/kbd&gt; another way to go to Terminal-Normal mode&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:tnoremap &amp;lt;Esc&amp;gt; &amp;lt;C-w&amp;gt;N&lt;/kbd&gt; map &lt;kbd&gt;Esc&lt;/kbd&gt; key to go to Terminal-Normal mode&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;kbd&gt;:&lt;/kbd&gt; go to Command-line mode from terminal window&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Depending on your shell, you can use the &lt;code&gt;exit&lt;/code&gt; command to end the terminal session. &lt;code&gt;Ctrl+d&lt;/code&gt; might work too.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; There are lot of features in this mode, see &lt;a href="https://vimhelp.org/terminal.txt.html"&gt;:h terminal.txt&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 18 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-16/</guid></item><item><title>XPiphany</title><link>https://cmdev.com/blog/2022-10-16-xpiphany/</link><description>I thought XP was chaos. Turns out, I was both right and wrong</description><author>The Cranky Developer on Crater Moon Development</author><pubDate>Mon, 17 Oct 2022 17:07:07 GMT</pubDate><guid isPermaLink="true">https://cmdev.com/blog/2022-10-16-xpiphany/</guid></item><item><title>Unit Testing Randomness</title><link>https://cmdev.com/blog/unit-testing-randomness/</link><description>Testing a (pseudo)random number generator</description><author>The Cranky Developer on Crater Moon Development</author><pubDate>Mon, 17 Oct 2022 07:23:00 GMT</pubDate><guid isPermaLink="true">https://cmdev.com/blog/unit-testing-randomness/</guid></item><item><title>XCheck at Meta: Why it exists and how it works</title><link>https://nindalf.com/posts/xcheck/</link><description>The article discusses the XCheck system at Meta (formerly Facebook) and its purpose in preventing accidental enforcement from affecting accounts that are known to be good.</description><author>Krishna's blog</author><pubDate>Sun, 16 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/xcheck/</guid></item><item><title>FOSDEM talks and emulation</title><link>https://anisse.astier.eu/talks-emulation.html</link><description>&lt;p&gt;In 2019 I gave a &lt;a href="https://archive.fosdem.org/2019/schedule/event/embeddedwithgo/"&gt;talk at FOSDEM in Brussels on the "music portal"&lt;/a&gt;, a device I built for my children as a toy that plays music. I wrote about the &lt;a href="awk-driven-iot.html"&gt;first version in awk here&lt;/a&gt;. The talk revolved around the specifics of the Go language and how it was …&lt;/p&gt;</description><author>Linux Engineer's random thoughts</author><pubDate>Sun, 16 Oct 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://anisse.astier.eu/talks-emulation.html</guid></item><item><title>Future Security Threats - Example One - The Threat from Stable Diffusion</title><link>https://mikewarot.blogspot.com/2022/10/future-security-threats-example-one.html</link><description>&lt;p&gt;I'm playing with &lt;a href="https://github.com/cmdr2/stable-diffusion-ui#installation" target="_blank"&gt;Stable Diffusion&lt;/a&gt;&amp;nbsp;on my PC, to see what kind of things it comes up with, and learn a bit more about the nature of AI. I've been trying to visualize the words of my friend Lloyd Smith, who well before his passing often said in jest&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;When I die... I want to be sat upright in a chair at a card table, on the surface of the moon, with a royal flush in my hands, and a shit eating grin on my face. That will give the astronomy students something fun to look for.&lt;/blockquote&gt;There have been quite a few thought provoking outputs, some of which worked out really well&lt;p&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVvhFPn_sdNZ5MkrvuG3f3PVEqAyKvZ75tphRYph7hxDYJVw3gRUmHPjvkHg8YORB_63I4fzK3_EpW25ZlDUNhUNsyY9x8z0QHOqwq7q0d9KTPTfkGBqy61nOCsJ3HT4_ytPFmUs1vQyQiK8jox9e5HU14TeROXerealizaDBqOjw8etrQ4Q/s512/Lloyd%20Smith%20-%20man_winning_poker_card_game__seated_at_a_table_on__8ab353f8_GFPGANv1.3.jpeg" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVvhFPn_sdNZ5MkrvuG3f3PVEqAyKvZ75tphRYph7hxDYJVw3gRUmHPjvkHg8YORB_63I4fzK3_EpW25ZlDUNhUNsyY9x8z0QHOqwq7q0d9KTPTfkGBqy61nOCsJ3HT4_ytPFmUs1vQyQiK8jox9e5HU14TeROXerealizaDBqOjw8etrQ4Q/s320/Lloyd%20Smith%20-%20man_winning_poker_card_game__seated_at_a_table_on__8ab353f8_GFPGANv1.3.jpeg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;But in browsing through them this morning, out of the 500+ images I've generated on this theme, I saw this&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyNOmCdz-2EPdB1nP3RySb9MDvUgnT0ZQS_USuAbg2acABUA2d0H2R4UJjz9F127sEPNNRcyURcPTqLucj58Qua8qajYvIISiLZ6DV9jYg-plnXA1eKVPffTW8oA2vMctPGO1GeeMzz5pHsYdPKD3k1BtL46Kz3DRRnKyKmrgmhOBtO83aGg/s512/sd%20-%20Watermark%20leakage%20from%20Stable%20Diffusion%20-%20Future%20Security%20Threat.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyNOmCdz-2EPdB1nP3RySb9MDvUgnT0ZQS_USuAbg2acABUA2d0H2R4UJjz9F127sEPNNRcyURcPTqLucj58Qua8qajYvIISiLZ6DV9jYg-plnXA1eKVPffTW8oA2vMctPGO1GeeMzz5pHsYdPKD3k1BtL46Kz3DRRnKyKmrgmhOBtO83aGg/s320/sd%20-%20Watermark%20leakage%20from%20Stable%20Diffusion%20-%20Future%20Security%20Threat.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Which immediately brought back to mind the &lt;a href="https://www.youtube.com/watch?v=7gvuqBORyBg" target="_blank"&gt;NDC Keynote Presentation by Laura Bell&lt;/a&gt; I watched last night, which addressed future security threats. One of the possibilities was the threat of curated data sets... and here it was in my own PC.&lt;br /&gt;&lt;div&gt;&lt;p&gt;I don't know how, but somewhere in this curated set of data, copyrights might have been broken. The future is here.&lt;/p&gt;&lt;/div&gt;</description><author>--Mike--</author><pubDate>Thu, 13 Oct 2022 19:40:37 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/10/future-security-threats-example-one.html</guid></item><item><title>CLI tip 17: common and unique lines</title><link>https://learnbyexample.github.io/tips/cli-tip-17/</link><description>&lt;p&gt;Consider these sample input files that are already sorted and the default output from &lt;code&gt;comm&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ paste colors_1.txt colors_2.txt
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Blue    Black
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Brown   Blue
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Orange  Green
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Purple  Orange
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Red     Pink
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Teal    Red
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;White   White
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ comm colors_1.txt colors_2.txt
&lt;/span&gt;&lt;span&gt;        &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Black
&lt;/span&gt;&lt;span&gt;                &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Blue
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Brown
&lt;/span&gt;&lt;span&gt;        &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Green
&lt;/span&gt;&lt;span&gt;                &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Orange
&lt;/span&gt;&lt;span&gt;        &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Pink
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Purple
&lt;/span&gt;&lt;span&gt;                &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Red
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Teal
&lt;/span&gt;&lt;span&gt;                &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;White
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following &lt;code&gt;comm&lt;/code&gt; options will help you construct solutions to get common and unique lines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-1&lt;/code&gt; suppress lines unique to the first file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-2&lt;/code&gt; suppress lines unique to the second file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-3&lt;/code&gt; suppress lines common to both the files&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# common lines
&lt;/span&gt;&lt;span&gt;$ comm &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;12&lt;/span&gt;&lt;span&gt; colors_1.txt colors_2.txt
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Blue
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Orange
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Red
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;White
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# lines unique to colors_2.txt
&lt;/span&gt;&lt;span&gt;$ comm &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;13&lt;/span&gt;&lt;span&gt; colors_1.txt colors_2.txt
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Black
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Green
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Pink
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the input files are not already sorted, or if you want to preserve the order of input lines, you can use &lt;code&gt;awk&lt;/code&gt; instead:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# common lines
&lt;/span&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'NR==FNR{a[$0]; next} $0 in a'&lt;/span&gt;&lt;span&gt; colors_1.txt colors_2.txt
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Blue
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Orange
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Red
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;White
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# lines unique to colors_2.txt
&lt;/span&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'NR==FNR{a[$0]; next} !($0 in a)'&lt;/span&gt;&lt;span&gt; colors_1.txt colors_2.txt
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Black
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Green
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Pink
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; You can also use &lt;code&gt;grep -Fxf colors_1.txt colors_2.txt&lt;/code&gt; (add &lt;code&gt;-v&lt;/code&gt; for unique lines) but this wouldn't scale well for larger input files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/cli-computing"&gt;Linux Command Line Computing&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 12 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-17/</guid></item><item><title>A database without dynamic memory allocation</title><link>http://notes.eatonphil.com/a-database-without-dynamic-memory.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://tigerbeetle.com/blog/a-database-without-dynamic-memory/"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Wed, 12 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/a-database-without-dynamic-memory.html</guid></item><item><title>The Absolute Best Way to Run Multiple npm Scripts in Parallel in 2022</title><link>https://www.swyx.io/parallel-npm-scripts</link><description>&lt;p&gt;Just a quick tutorial and explanation of how best to set up concurrently with named and colored log output since I had to look it up today.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Wed, 12 Oct 2022 01:18:03 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/parallel-npm-scripts</guid></item><item><title>What is artificial intelligence and what isn't?</title><link>https://iamnotarobot.substack.com/p/what-is-artificial-intelligence-and</link><description>Most people who talk about AI haven't spent much time thinking about what it means. What exactly is intelligence as an attribute of a software system?</description><author>I Am Not a Robot</author><pubDate>Mon, 10 Oct 2022 18:37:40 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/what-is-artificial-intelligence-and</guid></item><item><title>Checking back in on Blizzard</title><link>https://benovermyer.com/blog/2022/10/checking-back-in-on-blizzard/</link><description>&lt;p&gt;It's been &lt;a href="https://benovermyer.com/blog/2022/10/blizzard-is-dead-to-me"&gt;over a year&lt;/a&gt; since I swore off of Blizzard games. A lot has changed in that time. Many people have left the company, and they've made several changes that appear on the surface to indicate a better culture. They've also made some questionable decisions. I decided to give Blizzard another chance.&lt;/p&gt;
&lt;p&gt;This decision point happened a little over a week ago. I was talking with Sarah about the news of the impending release of Overwatch 2. Despite having avoided Blizzard games for a year, I never stopped checking the headlines on Polygon about what Blizzard Entertainment was up to. Mostly it was like watching a train wreck in slow motion. The release of Diablo Immortal was somehow worse than anyone could have predicted, with one of the most awful monetization schemes known to man. The last few major leaders for Overwatch left. There was some good, though. World of Warcraft's team actually seemed to be making positive progress.&lt;/p&gt;
&lt;p&gt;As I was mulling all this over with Sarah, I realized that enough had changed that I might be willing to give them another shot. It dawned on me, too, that bearing a grudge against a game company may not be the best way to encourage internal change at that game company. So the next day, after giving it a second round of thought, I decided to rescind my personal ban on Blizzard games and give it another go.&lt;/p&gt;
&lt;p&gt;I reinstalled Overwatch for the last full day of the game's life before it was shut down to make way for Overwatch 2. I even tried to livestream it, though it was only the next morning that I realized the stream had no sound. Playing Overwatch was like stretching muscles long unused - no game had ever filled that niche for me, though I tried Paladins for awhile. I enjoyed being back in it. It felt like greeting an estranged friend for the first time in a long time.&lt;/p&gt;
&lt;p&gt;I even bought the Collector's Edition for the new World of Warcraft expansion, since I own the CEs of every expansion. I only lack the CE for the original game. I'm waiting until later to begin playing that again, though. The expansion releases at the end of November, and while I still have a lot of the Shadowlands content to play through before it, I'm in no hurry.&lt;/p&gt;
&lt;p&gt;Diablo 2: Resurrected finally landed on my PC, too. I had preordered it before the ban went into effect, so I never played it. The graphics are impressive and it feels like my memories of the original. I really do hate managing potions, though. That never changed.&lt;/p&gt;
&lt;p&gt;Overwatch 2's launch was plagued by server problems, long queues, and a DDoS attack. I got to play it a little, and it seems to have the broad strokes down. There are tons of tiny little issues that irk me, though. Many of the new "legendary" skins are only variations of the basic skins, not complete reimaginings like all of the old legendaries. Further, they're extremely expensive compared to the old skins. I doubt I'll be collecting any of the new skins, or really even participating much in the new cosmetics shop. Too little value for too big of an expense. The gameplay itself, though, is pretty solid. I like the new Push mode.&lt;/p&gt;
&lt;p&gt;So, the games are fun enough. But what about the company's culture? For that, I have to reach out to some friends. We'll see what I learn. If the culture is changing then this may not be a temporary return for me.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Mon, 10 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/10/checking-back-in-on-blizzard/</guid></item><item><title>Estimating mathematical constants with Monte Carlo simulations</title><link>https://bytepawn.com/estimating-famous-mathematical-constants-with-monte-carlo-simulations.html</link><description>&lt;p&gt;I use simple Monte Carlo simulations to estimate some mathematical constants: √2, ϕ, e and π. &lt;br /&gt;&lt;br /&gt; &lt;img alt="." src="/images/1perx_e.png" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 09 Oct 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/estimating-famous-mathematical-constants-with-monte-carlo-simulations.html</guid></item><item><title>2022–10–08: Pinephone UART HW Issue</title><link>https://xnux.eu/log/#075</link><author>megi's PinePhone Development Log</author><pubDate>Sat, 08 Oct 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#075</guid></item><item><title>Python tip 17: counting frequency of items</title><link>https://learnbyexample.github.io/tips/python-tip-17/</link><description>&lt;p&gt;One of the ways to count the frequency of items is to make use of the &lt;code&gt;dict.get()&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;vehicles &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'jeep'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bike'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bus'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bike'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;hist &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;{}
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; for &lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;vehicles:
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span&gt;hist[v] &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;hist.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;get&lt;/span&gt;&lt;span&gt;(v, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;+ &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;hist
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'jeep'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bike'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bus'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's a solution using the built-in &lt;a href="https://docs.python.org/3/library/collections.html"&gt;collections&lt;/a&gt; module:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; from &lt;/span&gt;&lt;span&gt;collections &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;import &lt;/span&gt;&lt;span&gt;Counter
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;vehicles &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'jeep'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bike'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bus'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bike'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Counter&lt;/span&gt;&lt;span&gt;(vehicles)
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Counter&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bike'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'jeep'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bus'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;})
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Counter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'abracadabra'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Counter&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'b'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'r'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'c'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'d'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://stackoverflow.com/q/3496518/4082052"&gt;stackoverflow: using a dictionary to count items&lt;/a&gt; and &lt;a href="https://stackoverflow.com/q/2161752/4082052"&gt;stackoverflow: count frequency of elements&lt;/a&gt; for more ways to solve this problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Thu, 06 Oct 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-17/</guid></item><item><title>Implementing truly safe semaphores in rust</title><link>https://neosmart.net/blog/implementing-truly-safe-semaphores-in-rust/</link><description>&lt;p&gt;Discuss this article on r/rust or on Hacker News. Low-level or systems programming languages generally strive to provide libraries and interfaces that enable developers, boost productivity, enhance safety, provide resistance to misuse, and more &amp;#8212; all while trying to reduce &amp;#8230; &lt;a href="https://neosmart.net/blog/implementing-truly-safe-semaphores-in-rust/"&gt;Continue reading &lt;span class="meta-nav"&gt;&amp;#8594;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
The post &lt;a href="https://neosmart.net/blog/implementing-truly-safe-semaphores-in-rust/"&gt;Implementing truly safe semaphores in rust&lt;/a&gt; first appeared on &lt;a href="https://neosmart.net/blog"&gt;The NeoSmart Files&lt;/a&gt;.</description><author>The NeoSmart Files</author><pubDate>Mon, 03 Oct 2022 23:11:34 GMT</pubDate><guid isPermaLink="true">https://neosmart.net/blog/implementing-truly-safe-semaphores-in-rust/</guid></item><item><title>Common patterns in technical interviewing</title><link>https://bytepawn.com/common-patterns-in-technical-interviewing.html</link><description>&lt;p&gt;I will attempt to enumerate all the categories of questions commonly asked in technical interview loops, and my experience with them. &lt;br /&gt;&lt;br /&gt; &lt;img alt="." src="/images/interview-patterns.jpeg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 01 Oct 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/common-patterns-in-technical-interviewing.html</guid></item><item><title>Go install loop. The "clang" command requires the command line developer tools.</title><link>https://boyter.org/posts/golang-the-clang-command-requires-command-line-developer-tools/</link><description>&lt;p&gt;Recently on my M1 Macbook I ran into the following issue when trying to compile some Go code with C dependencies.&lt;/p&gt;
&lt;p&gt;&lt;img alt="The clang command requires the command line developer tools" src="https://boyter.org/static/the-clang-command-requires-command-line-developer-tools.png#center" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &amp;ldquo;clang&amp;rdquo; command requires the command line developer tools.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Being a Mac this also prompted me with a button I could click to install them. Naturally I clicked it, only to be prompted with the following.&lt;/p&gt;
&lt;p&gt;&lt;img alt="The clang command requires the command line developer tools" src="https://boyter.org/static/the-clang-command-requires-command-line-developer-tools-2.png#center" /&gt;&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Wed, 28 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/golang-the-clang-command-requires-command-line-developer-tools/</guid></item><item><title>Vim tip 15: moving within current line</title><link>https://learnbyexample.github.io/tips/vim-tip-15/</link><description>&lt;p&gt;Here are some of the Normal mode commands for moving within the current line:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;0&lt;/kbd&gt; move to the beginning of the current line (i.e. column number 1)
&lt;ul&gt;
&lt;li&gt;you can also use the &lt;kbd&gt;Home&lt;/kbd&gt; key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;^&lt;/kbd&gt; move to the beginning of the first non-blank character of the current line (useful for indented lines)&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;$&lt;/kbd&gt; move to the end of the current line
&lt;ul&gt;
&lt;li&gt;you can also use the &lt;kbd&gt;End&lt;/kbd&gt; key&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;3$&lt;/kbd&gt; move to the end of 2 lines below the current line&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;g_&lt;/kbd&gt; move to the last non-blank character of the current line&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;3|&lt;/kbd&gt; move to the third column character
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;|&lt;/kbd&gt; is same as &lt;kbd&gt;0&lt;/kbd&gt; or &lt;kbd&gt;1|&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 27 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-15/</guid></item><item><title>How good a particle physicist is GPT-3?</title><link>https://bytepawn.com/how-good-a-particle-physicist-is-gpt-3.html</link><description>&lt;p&gt;Here I will show a "conversation" with GPT-3 to gauge how good a particle physicist — or an illusion of a particle physicist — it is.&lt;br /&gt;&lt;br /&gt; &lt;img alt="GPT-3" src="/images/robot-einstein.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 24 Sep 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/how-good-a-particle-physicist-is-gpt-3.html</guid></item><item><title>Mike's law of capabilities</title><link>https://mikewarot.blogspot.com/2022/09/mikes-law-of-capabilities.html</link><description>&lt;pre style="overflow: auto; padding: 2px;"&gt;&lt;code style="background-color: #f6f6ef; font-size: 12px; white-space: pre-wrap;"&gt;Any sufficiently popular computing environment contains an ad hoc, informally-specified, bug-ridden, slow implementation of capability based security.&lt;/code&gt;
&lt;/pre&gt;In a recent Hacker News thread[1], I quoted from the source article&lt;br /&gt;&lt;blockquote&gt;Continuing a legacy is an honorable task, except in programming. &lt;/blockquote&gt;&lt;div&gt;This is the most important of the items in the list. The "upgrade or you're unclean" ethos has some very deep roots. It goes all the way down to the security model of our operating systems.&lt;/div&gt;&lt;div&gt;It was perfectly reasonable to assume that a user knew what they were doing with their own files back in the days when Unix was written. That wasn't assumed in the world of mainframes, which were designed to multiplex hardware across tens, hundreds, or even thousands of jobs. In mainframes, your job is explicitly given resources to use and a run time environment. No matter what went wrong, a job run for Acme Inc couldn't corrupt the files of Bob's Distributor. &lt;br /&gt;We don't have that... we've been lead to believe that we just have to be pure enough, our code has to be perfect enough, and defect free, in order to have safety. We blame everything except the OS, mostly because we don't want to cast doubt on the wisdom of Linus, and the sanctity of Linux.&lt;br /&gt;We recreate the mainframe model, over and over, in part, not in whole. It's like Greenspun's 10th rule[2].&lt;/div&gt;&lt;div&gt;Any sufficiently popular computing environment contains an ad hoc, informally-specified, bug-ridden, slow implementation of capability based security. That's why we have Virtual Machines, Containers, and now WASM... which I hope actually manages to fend off the stupidity of letting an application decide which files to access.&lt;/div&gt;&lt;div&gt;We need to make better choices. Legacies are a choice, lots of old stuff is tossed by kids all the time, the legacies are the good things kept from the past. Keeping legacies alive is a choice, let's chose wisely.&lt;br /&gt;&lt;br /&gt;[1]&amp;nbsp;https://news.ycombinator.com/item?id=32935466&lt;br /&gt;[2] https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule&lt;/div&gt;&lt;div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;</description><author>--Mike--</author><pubDate>Fri, 23 Sep 2022 16:31:23 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/09/mikes-law-of-capabilities.html</guid></item><item><title>Data Science Culture Doc</title><link>https://bytepawn.com/data-science-culture-doc.html</link><description>&lt;p&gt;I wrote a Culture Doc for the Data Science team I lead.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Culture doc" src="/images/maf-ds-culture1.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 23 Sep 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/data-science-culture-doc.html</guid></item><item><title>CLI tip 16: transpose tables</title><link>https://learnbyexample.github.io/tips/cli-tip-16/</link><description>&lt;p&gt;&lt;a href="https://www.gnu.org/software/datamash/"&gt;GNU datamash&lt;/a&gt; has plenty of nifty features for field based operations. Here's an example of transposing comma delimited data:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat scores.csv 
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Maths&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Physics&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Chemistry
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Ith&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Cy&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;97&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;98&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;95
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Lin&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;83&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;80
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Er&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;60&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;70&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;90
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ datamash &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;t, transpose &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;scores.csv 
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Ith&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Cy&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Lin&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Er
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Maths&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;97&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;60
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Physics&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;98&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;83&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;70
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Chemistry&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;95&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;80&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;90
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's an alternate solution using &lt;code&gt;tr&lt;/code&gt;, &lt;code&gt;wc&lt;/code&gt; and &lt;code&gt;pr&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# divide input into five parts and join them vertically
&lt;/span&gt;&lt;span&gt;$ seq &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; pr &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;5ts,
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;9
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;8&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# tr converts input table into single field per line
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# wc calculates number of rows and pr does the rest
&lt;/span&gt;&lt;span&gt;$ tr &lt;/span&gt;&lt;span style="color: #d07711;"&gt;',' '\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;scores.csv &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; pr &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;$(wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;l &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;scores.csv)ts,
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Ith&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Cy&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Lin&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Er
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Maths&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;97&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;60
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Physics&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;98&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;83&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;70
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Chemistry&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;95&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;80&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;90
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also &lt;a href="https://unix.stackexchange.com/q/308631/109046"&gt;unix.stackexchange: How to process an x-column text file to get a y-column one?&lt;/a&gt; for many more ways to deal with such problems. See &lt;a href="https://learnbyexample.github.io/cli-computation-gnu-datamash/"&gt;my blog post&lt;/a&gt; for examples and resource links on the GNU datamash command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/cli-computing"&gt;Linux Command Line Computing&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 21 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-16/</guid></item><item><title>Talk Notes for The End of Localhost (Infobip Shift 2022)</title><link>https://www.swyx.io/end-of-localhost-infobip</link><description>&lt;p&gt;I returned to Zadar!&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Mon, 19 Sep 2022 15:13:40 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/end-of-localhost-infobip</guid></item><item><title>Getting Senpai To Notice You</title><link>https://www.swyx.io/notice-me</link><description>&lt;p&gt;How to break the cold start problem in content creation as a new entrant to any field, and getting the leaders of that field to at least read your writing and know your name.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sun, 18 Sep 2022 15:05:24 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/notice-me</guid></item><item><title>A minimal distributed key-value database with Hashicorp's Raft library</title><link>http://notes.eatonphil.com/minimal-key-value-store-with-hashicorp-raft.html</link><description>&lt;p&gt;When I wrote the "&lt;a href="/distributed-postgres.html"&gt;build a distributed PostgreSQL proof of
concept&lt;/a&gt;" post I first had to figure out
how to use &lt;a href="https://github.com/hashicorp/raft"&gt;Hashicorp's Raft
implementation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There weren't any examples I could find in the Hashicorp repo
itself. And the only example I &lt;em&gt;could&lt;/em&gt; find was Philip O'Toole's
&lt;a href="https://github.com/otoolep/hraftd"&gt;hraftd&lt;/a&gt;. It's great! However, I
have a hard time following multi-file examples in general.&lt;/p&gt;
&lt;p&gt;So I built my own &lt;a href="https://github.com/eatonphil/raft-example"&gt;single-file
example&lt;/a&gt;. It's not perfect
but it helped me get started and may help you too. We'll walk through
that code, ~260 lines of Go, in this post.&lt;/p&gt;
&lt;p&gt;The key-value database will only be able to set keys, not delete
them. But it will be able to overwrite existing entries. And it will
expose this distributed key-value database over an HTTP API.&lt;/p&gt;
&lt;p&gt;Here's a sample interaction it will be able to support.&lt;/p&gt;
&lt;p&gt;Terminal 1:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./raft-example&lt;span class="w"&gt; &lt;/span&gt;--node-id&lt;span class="w"&gt; &lt;/span&gt;node1&lt;span class="w"&gt; &lt;/span&gt;--raft-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2222&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--http-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8222&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Terminal 2:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./raft-example&lt;span class="w"&gt; &lt;/span&gt;--node-id&lt;span class="w"&gt; &lt;/span&gt;node2&lt;span class="w"&gt; &lt;/span&gt;--raft-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2223&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--http-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8223&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Terminal 3, tell 1 to have 2 follow it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8222/join?followerAddr=localhost:2223&amp;amp;followerId=node2'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Terminal 3, now add a key:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-X&lt;span class="w"&gt; &lt;/span&gt;POST&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8222/set'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'{&amp;quot;key&amp;quot;: &amp;quot;x&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;23&amp;quot;}'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-H&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Terminal 3, now get the key from either server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8222/get?key=x'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;23&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8223/get?key=x'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;23&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's make it happen!&lt;/p&gt;
&lt;h3 id="eine-kleine-background"&gt;Eine kleine background&lt;/h3&gt;&lt;p&gt;Raft is an algorithm for managing a replicated (basically append-only)
log over a cluster of nodes. When you combine this with a state
machine you get a stateful, distributed application. Log entries act
as commands for the state machine. When a node in the Raft cluster
crashes, it is brought up to date by sending (also called "replaying")
all commands in the log through the state machine.&lt;/p&gt;
&lt;p&gt;This can be made more efficient by implementing an
application-specific concept of state snapshots. But since snapshots
are just an optimization, we'll skip it entirely to keep this
application simple.&lt;/p&gt;
&lt;p&gt;If you want the details, just &lt;a href="https://raft.github.io/raft.pdf"&gt;read the Raft
paper&lt;/a&gt;! It is surprisingly
accessible, especially as a user.&lt;/p&gt;
&lt;h3 id="our-app"&gt;Our app&lt;/h3&gt;&lt;p&gt;In our distributed key-value application, commands will be a
serialized struct with a key and a value. The state machine will take
each struct and set the key to the value in memory. Thus after
replaying the entire log (and continuing to apply future log entries),
each node will have an in-memory key-value store that is up to date
with all other nodes in the cluster.&lt;/p&gt;
&lt;p&gt;Note that although each node's key-value store will only be in memory,
it will be backed by the durable append-only log! So with, Raft each
in-memory key-value store will still be durable.&lt;/p&gt;
&lt;p&gt;Let's get things set up in a file, &lt;code&gt;main.go&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;io&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;net&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;sync&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;time&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/hashicorp/raft&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/hashicorp/raft-boltdb&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="the-state-machine"&gt;The state machine&lt;/h3&gt;&lt;p&gt;The state machine acts on an in-memory key-value store.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kvFsm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are three operations this Raft library wants us to implement on
our state machine struct.&lt;/p&gt;
&lt;h4 id="apply"&gt;Apply&lt;/h4&gt;&lt;p&gt;The Apply operation is sent to basically-up-to-date nodes to keep them
up to date. An Apply call is made for each new log the leader commits.&lt;/p&gt;
&lt;p&gt;Each log message will contain a key and value to store in the
in-memory key-value store.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setPayload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;kvFsm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogCommand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setPayload&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not parse payload: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown raft log type: %#v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we're reading a log in a custom format. Later on down in the HTTP
server we'll write the part that submits that log in this custom
format.&lt;/p&gt;
&lt;p&gt;The Raft library just cares that logs are (opaque) bytes. Whatever
format works.&lt;/p&gt;
&lt;h4 id="restore"&gt;Restore&lt;/h4&gt;&lt;p&gt;The Restore operation reads all logs and applies them to the state
machine.&lt;/p&gt;
&lt;p&gt;It looks very similar to the &lt;code&gt;Apply&lt;/code&gt; function we just wrote except for
that this operates on an &lt;code&gt;io.ReadCloser&lt;/code&gt; of serialized log data rather
than the high-level &lt;code&gt;raft.Log&lt;/code&gt; struct.&lt;/p&gt;
&lt;p&gt;And most importantly, and unlike the &lt;code&gt;Apply&lt;/code&gt; function, &lt;code&gt;Restore&lt;/code&gt; must
reset all local state.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;kvFsm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Restore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReadCloser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Must always restore from a clean state!!&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;More&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setPayload&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not decode payload: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;io.ReadCloser&lt;/code&gt; represents the latest snapshot or the beginning of
time if there are no snapshots.&lt;/p&gt;
&lt;h4 id="snapshot"&gt;Snapshot&lt;/h4&gt;&lt;p&gt;We won't implement this. But to satisfy the Go interface we must have
empty some functions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshotNoop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshotNoop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SnapshotSink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshotNoop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;kvFsm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FSMSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshotNoop&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  I &lt;em&gt;think&lt;/em&gt; this is a correct noop. If we implemented a real
  snapshot we'd serialize the current key-value state, and &lt;code&gt;raft.SnapshotSink.Write()&lt;/code&gt; it
  to the &lt;code&gt;raft.SnapshotSink&lt;/code&gt;. That sink, in turn, is what is passed (as
  an &lt;code&gt;io.ReadCloser&lt;/code&gt;) to the &lt;code&gt;Restore&lt;/code&gt; method above.
  &lt;br /&gt;
  &lt;br /&gt;
  So it must be that when we do not call &lt;code&gt;raft.SnapshotSink.Close()&lt;/code&gt;, &lt;a href="https://pkg.go.dev/github.com/hashicorp/raft#FSMSnapshot"&gt;as the docs suggest&lt;/a&gt;,
  no snapshot gets recorded.
  &lt;br /&gt;
  &lt;br /&gt;
  Since we aren't implementing snapshots, the Raft
  library must be doing its own serialization, writing each message's
  bytes directly to some sink.
  &lt;br /&gt;
  &lt;br /&gt;
  If I'm wrong, &lt;a href="mailto:phil@eatonphil.com"&gt;feel free to correct me&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;That's it for the state machine!&lt;/p&gt;
&lt;h3 id="raft-node-initialization"&gt;Raft node initialization&lt;/h3&gt;&lt;p&gt;In order to start the Raft library behavior for each node, we need a
whole bunch of boilerplate for Raft library initialization.&lt;/p&gt;
&lt;p&gt;Each Raft node needs a TCP port that it uses to communicate with other
nodes in the same cluster.&lt;/p&gt;
&lt;p&gt;Each node starts out in a single-node cluster where it is the
leader. Only when told to (and given the address of other nodes) does
there become a multi-node cluster.&lt;/p&gt;
&lt;p&gt;Each node also needs a permanent store for the append-only log. The
Hashicorp Raft library suggests
&lt;a href="https://github.com/hashicorp/raft-boltdb"&gt;boltdb&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setupRaft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raftAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;kvFsm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Raft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MkdirAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ModePerm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raftboltdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewBoltStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bolt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create bolt store: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;snapshots&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewFileSnapshotStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;snapshot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create snapshot store: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tcpAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResolveTCPAddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tcp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raftAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not resolve address: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewTCPTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raftAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tcpAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create tcp transport: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;raftCfg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DefaultConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;raftCfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LocalID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServerID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewRaft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raftCfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshots&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create raft instance: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Cluster consists of unjoined leaders. Picking a leader and&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// creating a real cluster is done manually after startup.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BootstrapCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Servers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServerID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LocalAddr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let's dig into how nodes learn about each other.&lt;/p&gt;
&lt;h3 id="an-http-api"&gt;An HTTP API&lt;/h3&gt;&lt;p&gt;This key-value store application will have an HTTP API serving two purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cluster management: telling a leader to add followers&lt;/li&gt;
&lt;li&gt;Key-value storage: setting and getting keys&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Raft&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="cluster-management"&gt;Cluster management&lt;/h4&gt;&lt;p&gt;In this library, the leader is told to add other nodes as its
follower. (This feels backwards to me, but it is what it is!)&lt;/p&gt;
&lt;p&gt;For this, the library requires a node ID and its internal TCP port for
Raft messages.&lt;/p&gt;
&lt;p&gt;These will both be parameters we give each node later on when the node
process is started.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;joinHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;followerId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;followerId&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;followerAddr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;followerAddr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;raft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Leader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Not the leader&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddVoter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;followerId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;raft&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;followerAddr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Failed to add follower: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="key-value-storage"&gt;Key-value storage&lt;/h4&gt;&lt;p&gt;This part of the HTTP API exposes setting and getting.&lt;/p&gt;
&lt;h5 id="set"&gt;Set&lt;/h5&gt;&lt;p&gt;Setting is where, instead of modifying the local database directly, we
pass a message to the Raft cluster to store a log that contains the
key and value.&lt;/p&gt;
&lt;p&gt;Since we read log messages in &lt;code&gt;kvFsm.Apply&lt;/code&gt; and &lt;code&gt;kvFsm.Restore&lt;/code&gt; as a
JSON encoding of the &lt;code&gt;setPayload&lt;/code&gt; struct we created, we must write log
messages like so as well. Or, specifically in this case, we just
expect that the user passes a JSON body that matches the &lt;code&gt;setPayload&lt;/code&gt;
struct.&lt;/p&gt;
&lt;p&gt;Then we call &lt;code&gt;Apply&lt;/code&gt; on the Raft instance with the log message to get
this process going.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not read key-value in http request: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;future&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Blocks until completion&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not write key-value: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not write key-value, application: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  I'm not completely sure if `future.Response()` is supposed to be
  called from inside the `future.Error()` error block. You
  can &lt;a href="https://pkg.go.dev/github.com/hashicorp/raft#ApplyFuture"&gt;see
  the docs&lt;/a&gt; for yourself.
&lt;/p&gt;&lt;h5 id="get"&gt;Get&lt;/h5&gt;&lt;p&gt;If we wanted to be completely consistent we would need to pass a
&lt;code&gt;read&lt;/code&gt; message through to the Raft cluster and check its result for a
key's value. We'd need to implement that &lt;code&gt;read&lt;/code&gt; message in the state
machine.&lt;/p&gt;
&lt;p&gt;But if we don't care strongly about consistency for reads we can just
read the local in-memory store, skipping the Raft cluster.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;`json:&amp;quot;data&amp;quot;`&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not encode key-value in http response: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that's it for the server!&lt;/p&gt;
&lt;h3 id="configuration"&gt;Configuration&lt;/h3&gt;&lt;p&gt;Let's throw together a quick helper for grabbing configuration from
the CLI.&lt;/p&gt;
&lt;p&gt;When the process is started, each node must be configured
with a Raft-level TCP address, a Raft-level unique node ID, and an
HTTP address (for our application).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;httpPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;raftPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--node-id&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--http-port&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--raft-port&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raftPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Missing required parameter: --node-id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raftPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Missing required parameter: --raft-port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Missing required parameter: --http-port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And finally, the &lt;code&gt;main()&lt;/code&gt; that brings it all together.&lt;/p&gt;
&lt;h3 id="main"&gt;main&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;kvFsm&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dataDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MkdirAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ModePerm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create data directory: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setupRaft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;raft&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;localhost:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raftPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/set&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/get&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/join&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;joinHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Build it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tidy&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And give it a shot. :)&lt;/p&gt;
&lt;p&gt;Terminal 1:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./raft-example&lt;span class="w"&gt; &lt;/span&gt;--node-id&lt;span class="w"&gt; &lt;/span&gt;node1&lt;span class="w"&gt; &lt;/span&gt;--raft-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2222&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--http-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8222&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Terminal 2:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./raft-example&lt;span class="w"&gt; &lt;/span&gt;--node-id&lt;span class="w"&gt; &lt;/span&gt;node2&lt;span class="w"&gt; &lt;/span&gt;--raft-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2223&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--http-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8223&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Terminal 3, tell 1 to have 2 follow it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8222/join?followerAddr=localhost:2223&amp;amp;followerId=node2'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Terminal 3, now add a key:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-X&lt;span class="w"&gt; &lt;/span&gt;POST&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8222/set'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'{&amp;quot;key&amp;quot;: &amp;quot;x&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;23&amp;quot;}'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-H&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Terminal 3, now get the key from either server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8222/get?key=x'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;23&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8223/get?key=x'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;23&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we're golden!&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Following up on that &amp;quot;build a distributed postgres&amp;quot; post I wanted to write down a shorter intro to building a stateful, distributed application using Hashicorp's Raft library.&lt;br /&gt;&lt;br /&gt;So, here's a new blog post!&lt;br /&gt;&lt;br /&gt;Also, try reading the Raft paper! It's not bad 😀&lt;a href="https://t.co/C4S3uzxm0W"&gt;https://t.co/C4S3uzxm0W&lt;/a&gt; &lt;a href="https://t.co/L3Wwawe0UC"&gt;pic.twitter.com/L3Wwawe0UC&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1571662239559716865?ref_src=twsrc%5Etfw"&gt;September 19, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sat, 17 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/minimal-key-value-store-with-hashicorp-raft.html</guid></item><item><title>Profile on Livecycle.io Devx Project</title><link>https://www.swyx.io/profile-on-livecycleio-devx-project</link><description>&lt;p&gt;I was interviewed for Livecycle's DevX interview series &lt;a href="https://livecycle.io/blogs/devx-project-swyx/"&gt;here&lt;/a&gt;. Reproducing for posterity.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Thu, 15 Sep 2022 19:44:19 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/profile-on-livecycleio-devx-project</guid></item><item><title>Visualizing how S3 deletes 1 billion objects with Athena and Rust</title><link>https://tomforb.es/blog/visualizing-s3-deletions/</link><description>A few weeks ago I had the chance to delete 1 petabyte of data spread across 1 billion objects from S3. Well, actually 940 million, but close enough to the click-baitable 1 billion. I thought it would be interesting challenge to try and visualize the execution of these deletions and possibly gain som...</description><author>Tom Forbes</author><pubDate>Thu, 15 Sep 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://tomforb.es/blog/visualizing-s3-deletions/</guid></item><item><title>Python tip 16: delete list elements using index or slice</title><link>https://learnbyexample.github.io/tips/python-tip-16/</link><description>&lt;p&gt;The &lt;code&gt;pop()&lt;/code&gt; method removes the last element of a &lt;code&gt;list&lt;/code&gt; by default. You can pass an index to delete that specific item and the list will be automatically re-arranged. Return value is the element being deleted.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;primes &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;11&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;primes.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;pop&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;11
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;primes
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;student &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'learnbyexample'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2022&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Linux'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Vim'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Python'&lt;/span&gt;&lt;span&gt;]]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;student.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;pop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2022
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;student[&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;].&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;pop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Vim'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;student
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'learnbyexample'&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Linux'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Python'&lt;/span&gt;&lt;span&gt;]]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To remove multiple elements using slicing notation, use the &lt;code&gt;del&lt;/code&gt; statement. Unlike the &lt;code&gt;pop()&lt;/code&gt; method, you won't get the elements being deleted as the return value.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;books &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cradle'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'mistborn'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'legends &amp;amp; lattes'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'sourdough'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; del &lt;/span&gt;&lt;span&gt;books[&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;books
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cradle'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'mistborn'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'legends &amp;amp; lattes'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; del &lt;/span&gt;&lt;span&gt;books[:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;books
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'legends &amp;amp; lattes'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;student &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'learnbyexample'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2022&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Linux'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Vim'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Python'&lt;/span&gt;&lt;span&gt;]]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; del &lt;/span&gt;&lt;span&gt;student[&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;][&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;student
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'learnbyexample'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2022&lt;/span&gt;&lt;span&gt;, [&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Linux'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Python'&lt;/span&gt;&lt;span&gt;]]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 14 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-16/</guid></item><item><title>Text-to-image software: a piano or a digital camera?</title><link>https://iamnotarobot.substack.com/p/text-to-image-software-a-piano-or</link><description>Some technologies make it possible for extremely talented people to create new forms of expression. Are we witnessing one?</description><author>I Am Not a Robot</author><pubDate>Wed, 14 Sep 2022 00:56:58 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/text-to-image-software-a-piano-or</guid></item><item><title>Developing Raycast Extensions</title><link>https://3059274a.danpalmer-me.pages.dev/2022-09-13-raycast-extension-dev/</link><description>&lt;p&gt;I&amp;rsquo;ve just started using Raycast, an application launcher for macOS. Like every other launcher before it, it does a lot more than just launch applications, and most of that functionality comes from extensions. Also like several other launchers before it, I decided to have a go at writing an extension and see what the process is like.&lt;/p&gt;
&lt;p&gt;Back in the mid-2000s I was an avid user of Quicksilver. It was the first launcher I used, and was quite extensible, but extensions were native code (typically Objective-C) written against the Apple developer APIs, in Xcode, bundled up and injected into Quicksilver in a sort of plugin model. Writing extensions was cumbersome, poorly documented, and had a relatively long feedback cycle.&lt;/p&gt;</description><author>Dan Palmer</author><pubDate>Tue, 13 Sep 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://3059274a.danpalmer-me.pages.dev/2022-09-13-raycast-extension-dev/</guid></item><item><title>Introduction to Micro-Optimization</title><link>https://specbranch.com/posts/intro-to-micro-optimization/</link><description>&lt;p&gt;A modern CPU is an incredible machine.  It can execute many instructions at the same time, it can
re-order instructions to ensure that memory accesses and dependency chains don't impact performance
too much, it contains hundreds of registers, and it has huge areas of silicon devoted to predicting
which branches your code will take.  However, if you have a tight loop and you are interested in
optimizing the hell out of it, the same mechanisms that make your code run fast can make your job
very difficult.  They add a lot of complexity that can make it hard to figure out how to optimize a
function, and they can also create local optima that trap you into a less efficient solution.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Sun, 11 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/intro-to-micro-optimization/</guid></item><item><title>Write Your Own Task Queue</title><link>https://3059274a.danpalmer-me.pages.dev/2022-09-10-write-your-own-task-queue/</link><description>&lt;p&gt;This is not a tutorial on &lt;em&gt;how&lt;/em&gt; to write your own task queue, but rather an attempt to convince you that you &lt;em&gt;should&lt;/em&gt; write your own.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s a &amp;ldquo;task queue&amp;rdquo; in this context? For the purposes of this post, a task queue is a system for performing work out of band from a user interaction, often at some later time. Typically this is a core component of many web apps, and is used for performing long running tasks or things that can fail and may need to be retried like sending emails.&lt;/p&gt;</description><author>Dan Palmer</author><pubDate>Sat, 10 Sep 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://3059274a.danpalmer-me.pages.dev/2022-09-10-write-your-own-task-queue/</guid></item><item><title>10x-ing Svelte (Svelte Summit 2022 Talk Notes)</title><link>https://www.swyx.io/svelte-2022</link><description>&lt;p&gt;Some show notes for my Svelte Summit talk for those who are looking for all the references and cut content.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Fri, 09 Sep 2022 11:50:53 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/svelte-2022</guid></item><item><title>Decompiling Java, Excel and the Vista TCP/IP stack</title><link>https://boyter.org/posts/decompiling-java-excel-and-the-vista-tcpip-stack/</link><description>&lt;p&gt;Working for a large corporate company as a mid level developer is generally rather boring. Churn out some CRUD applications. Write ETL as businesses live on data (usually processed in excel). Meetings that are meant to resolve things but just result in more meetings.&lt;/p&gt;
&lt;p&gt;So in short, it is usually boring. However occasionally you get some sort of interesting problem, especially if you gain a reputation for actually solving them.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Fri, 09 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/decompiling-java-excel-and-the-vista-tcpip-stack/</guid></item><item><title>Tools, craftsmanship and mastery</title><link>https://blog.bayindirh.io/blog/tools-craftsmanship-and-mastery/</link><description>&lt;p&gt;There are things which mesmerizes me, with no end. One of them is watching humble people who are good at what they're doing. Being calm, confident and efficient while doing high quality work has a particular charm to it, regardless of the discipline they're in.&lt;/p&gt;
&lt;p&gt;Honestly, I have been studying these people on and off for quite some time. It's not a scientific study, but more of an informed observation, and I think I have found the things which makes these people tick.&lt;/p&gt;
&lt;p&gt;Most important of all is, these people are devoted to their crafts. They like what they're doing with a well refined love, with a deep respect added at healthy amounts. When they start working on something, this feeling emanates from them. A deep concentration with a subtle sense of joy, combined with unwavering professionalism and focus for high quality results become palpable in the air around them.&lt;/p&gt;
&lt;p&gt;Almost all these people are doing their crafts for a long time. They are used to ins and outs and peculiar details of their crafts. They don't get puzzled when something goes different than they expect, because they know what to do. They adjust and continue. This is rooted on experience per my observations. They know what might happen and what might not, and are mentally prepared at every step.&lt;/p&gt;
&lt;p&gt;Another common thing among these people are tool usage habits. The tools they use are well worn. They might be handed down from a generation earlier, or are using what they got for a long time. In every case the craft and the tool has evolved and transformed together, expanding what's possible with the tool and the craft itself. Even another person who get the very same tool can't use it the same way, because the tool at hand requires mastery and experience to wield that efficiently and productively.&lt;/p&gt;
&lt;p&gt;Last but not the least, these craftsman solve some of their problems once, and for all. Tools get fixed, methods solidified, procedures perfected. They internalize the things they do in a manner which limits them in numbers but maximizes in flexibility. They can get a new technique if what they have doesn't fit the bill, but they'll try to evolve what they have first. As a result, these people build a deep wisdom, appreciation and feeling for what they do, how they do and the results they get. This makes them distinguished individuals with a different sense about what they do, the results they get, the knowledge they embody and transfer to others.&lt;/p&gt;
&lt;p&gt;These kinds of people deserve to be observed by hours on end with delight and a keen interest on what they do, and how they achieve what they achieve.&lt;/p&gt;
&lt;p&gt;And honestly, I aspire to be one of these people.&lt;/p&gt;
&lt;p&gt;Maybe we should all aspire to be like that at some point, I have no idea.&lt;/p&gt;
&lt;p&gt;Until next time,&lt;/p&gt;
&lt;p&gt;Be kind.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Fri, 09 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/tools-craftsmanship-and-mastery/</guid></item><item><title>Vim tip 14: horizontal and vertical splits</title><link>https://learnbyexample.github.io/tips/vim-tip-14/</link><description>&lt;p&gt;You can have multiple windows within the same tab page.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:split filename&lt;/kbd&gt; open file for editing in a new horizontal window, above the current window
&lt;ul&gt;
&lt;li&gt;you can also use &lt;kbd&gt;:sp&lt;/kbd&gt; instead of &lt;kbd&gt;:split&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:set splitbelow&lt;/kbd&gt; open horizontal splits below the current window&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:vsplit filename&lt;/kbd&gt; open file for editing in a new vertical window, to the left of the current window
&lt;ul&gt;
&lt;li&gt;you can also use &lt;kbd&gt;:vs&lt;/kbd&gt; instead of &lt;kbd&gt;:vsplit&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:set splitright&lt;/kbd&gt; open vertical splits to the right of the current window&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are some shortcuts to navigate between windows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;kbd&gt;w&lt;/kbd&gt; switch to the below/right window for horizontal/vertical splits respectively
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; also performs the same function&lt;/li&gt;
&lt;li&gt;switches to the first split if you are on the last split&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;kbd&gt;W&lt;/kbd&gt; switch to the above/left window for horizontal/vertical splits respectively
&lt;ul&gt;
&lt;li&gt;switches to the last split if you are on the first split&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;code&gt;hjkl&lt;/code&gt; or arrow keys, switch in the respective direction&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;kbd&gt;t&lt;/kbd&gt; or &lt;kbd&gt;b&lt;/kbd&gt; switch to the top (first) or bottom (last) window&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;w&lt;/kbd&gt; followed by &lt;code&gt;HJKL&lt;/code&gt; (uppercase), moves the current split to the farthest possible location in the respective direction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; If filename is not provided, the current one is used.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Vim adds a highlighted horizontal bar containing the filename for each split.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 06 Sep 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-14/</guid></item><item><title>The God Endpoints will continue until morale improves</title><link>https://www.swyx.io/god-endpoints</link><description>&lt;p&gt;a brief meditation on why we keep trying to build God Endpoints and why we will fail until we figure out interfaces.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Tue, 06 Sep 2022 01:33:58 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/god-endpoints</guid></item><item><title>How good a Data Scientist is GPT-3? - Part II</title><link>https://bytepawn.com/how-good-a-data-scientist-is-gpt-3-part-ii.html</link><description>&lt;p&gt;I have further "conversations" with GPT-3, this time asking more difficult questions about real-world Data Science projects I have personally worked on.&lt;br /&gt;&lt;br /&gt; &lt;img alt="GPT-3" src="/images/gpt-3-other.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 03 Sep 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/how-good-a-data-scientist-is-gpt-3-part-ii.html</guid></item><item><title>Paradigm Lost (CascadiaJS 2022 Talk Notes)</title><link>https://www.swyx.io/paradigm-lost</link><description>&lt;p&gt;Some show notes for my CascadiaJS talk for those who are looking for all the references and cut content.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Thu, 01 Sep 2022 23:22:47 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/paradigm-lost</guid></item><item><title>CLI tip 15: text generation with printf and brace expansion</title><link>https://learnbyexample.github.io/tips/cli-tip-15/</link><description>&lt;p&gt;You can use &lt;a href="https://www.gnu.org/software/bash/manual/bash.html#Brace-Expansion"&gt;brace expansion&lt;/a&gt; for generating a sequence of numbers and alphabets. &lt;code&gt;printf&lt;/code&gt; helps you to display multiple arguments using the same format specifier. For example:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ echo {&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;..&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1 2 3
&lt;/span&gt;&lt;span&gt;$ echo {&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;..&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;}{a&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;..&lt;/span&gt;&lt;span&gt;b}
&lt;/span&gt;&lt;span&gt;1a 1b 2a 2b
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;\n'&lt;/span&gt;&lt;span&gt; apple banana cherry
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;banana
&lt;/span&gt;&lt;span&gt;cherry
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Combining the two, you can generate multiple lines of text. Here are some examples:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;\n'&lt;/span&gt;&lt;span&gt; id_{&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;..&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;id_3
&lt;/span&gt;&lt;span&gt;id_2
&lt;/span&gt;&lt;span&gt;id_1
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;\n'&lt;/span&gt;&lt;span&gt; item_{&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;..&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;120&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;..&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;item_100
&lt;/span&gt;&lt;span&gt;item_104
&lt;/span&gt;&lt;span&gt;item_108
&lt;/span&gt;&lt;span&gt;item_112
&lt;/span&gt;&lt;span&gt;item_116
&lt;/span&gt;&lt;span&gt;item_120
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's a practical example:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# the string before %.s is repeated based on the number of arguments
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'x &lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%.s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt; a b c
&lt;/span&gt;&lt;span&gt;x x x 
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-- &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'- &lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%.s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;' &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;..&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;- - - - - 
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# same as: seq 10 | paste -d, - - - - -
&lt;/span&gt;&lt;span&gt;$ seq &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; paste &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;d, $(&lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-- &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'- &lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%.s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;' &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;..&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;})
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;8&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;9&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ n=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5
&lt;/span&gt;&lt;span&gt;$ seq &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; paste &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;d, $(&lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-- &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'- &lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%.s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt; $(seq &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;$n&lt;/span&gt;&lt;span&gt;))
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;8&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;9&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ n=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2
&lt;/span&gt;&lt;span&gt;$ seq &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; paste &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;d, $(&lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-- &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'- &lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%.s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt; $(seq &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;$n&lt;/span&gt;&lt;span&gt;))
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;8
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;9&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://stackoverflow.com/q/5349718/4082052"&gt;this stackoverflow thread&lt;/a&gt; for other alternatives, avoiding &lt;code&gt;printf&lt;/code&gt; for large numbers, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/cli-computing"&gt;Linux Command Line Computing&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 31 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-15/</guid></item><item><title>Selecting parts of a podcast</title><link>https://rjp.is/blogging/posts/2022/08/filtering-rss/</link><description>In which we filter some RSS.</description><author>infrequent oscillations</author><pubDate>Tue, 30 Aug 2022 21:42:33 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2022/08/filtering-rss/</guid></item><item><title>What I learned from Magnus Carlsen</title><link>https://iamnotarobot.substack.com/p/what-i-learned-from-magnus-carlsen</link><description>A short review of the podcast episodes I listened to in the past week, so you know which to skip</description><author>I Am Not a Robot</author><pubDate>Mon, 29 Aug 2022 20:59:53 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/what-i-learned-from-magnus-carlsen</guid></item><item><title>Update to Update to Portals</title><link>https://rjp.is/blogging/posts/2022/08/update-to-update-to-portals/</link><description>In which we update our updated portals.</description><author>infrequent oscillations</author><pubDate>Mon, 29 Aug 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2022/08/update-to-update-to-portals/</guid></item><item><title>Some of the more annoying Go bugs I have dealt with</title><link>https://boyter.org/posts/more-annoying-go-bugs/</link><description>&lt;p&gt;Thought I would write done some of the more annoying/interesting software bugs I have had to deal with recently.&lt;/p&gt;
&lt;p&gt;Both were dealing with an archive system where large amounts of video/audio/images are uploaded into, then searchable. It allows the editing of metadata for each type of content, as well sending to external systems.&lt;/p&gt;
&lt;h3 id="problem-1"&gt;Problem #1&lt;/h3&gt;
&lt;p&gt;When a record is being edited a flag &amp;ldquo;This is being edited&amp;rdquo; is added to the record and removed on save. However randomly the flag would not be removed, and sometimes additional flags would appear. This was implemented as a &amp;ldquo;cheap&amp;rdquo; version of optimistic locking that worked within the application requirements.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Mon, 29 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/more-annoying-go-bugs/</guid></item><item><title>What if your Index Page was Smart?</title><link>https://www.swyx.io/smart-indexes</link><description>&lt;p&gt;Let's rethink the humble Index Page from first principles.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sat, 27 Aug 2022 03:50:52 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/smart-indexes</guid></item><item><title>Mark Zuckerberg explains how he's building the Metaverse. Does he know why?</title><link>https://iamnotarobot.substack.com/p/mark-zuckerberg-explains-how-hes</link><description>I just listened to an interview with Mark Zuckerberg on the Joe Rogan podcast.</description><author>I Am Not a Robot</author><pubDate>Fri, 26 Aug 2022 20:50:21 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/mark-zuckerberg-explains-how-hes</guid></item><item><title>Python tip 15: string transliteration</title><link>https://learnbyexample.github.io/tips/python-tip-15/</link><description>&lt;p&gt;The &lt;code&gt;str.translate()&lt;/code&gt; method accepts a table of codepoints (numerical value of a character) mapped to another character or codepoint. Map to &lt;code&gt;None&lt;/code&gt; for characters that have to be deleted. You can use the &lt;a href="https://docs.python.org/3/library/functions.html#ord"&gt;ord()&lt;/a&gt; built-in function to get the codepoint of characters. Or, you can use the &lt;code&gt;str.maketrans()&lt;/code&gt; method to generate the mapping for you.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;ord&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;97
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;ord&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'A'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;65
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;greeting &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'have a nice day'
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# map 'a' to 'A', 'e' to 'E' and 'i' to None
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;greeting.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;translate&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;97&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;65&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;101&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'E'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;105&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;None&lt;/span&gt;&lt;span&gt;})
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'hAvE A ncE dAy'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# first and second arguments specify the one-to-one mapping of characters
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# third argument is optional, specifies characters to be deleted
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;str&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;maketrans&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ae'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'AE'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'i'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;97&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;65&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;101&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;69&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;105&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;None&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;greeting.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;translate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #a2a001;"&gt;str&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;maketrans&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ae'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'AE'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'i'&lt;/span&gt;&lt;span&gt;))
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'hAvE A ncE dAy'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href="https://docs.python.org/3/library/string.html"&gt;string module&lt;/a&gt; has a collection of constants that are often useful in text processing. Here's an example of deleting punctuation characters:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; from &lt;/span&gt;&lt;span&gt;string &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;import &lt;/span&gt;&lt;span&gt;punctuation
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;punctuation
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'!&amp;quot;#$%&amp;amp;&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\'&lt;/span&gt;&lt;span style="color: #d07711;"&gt;()*+,-./:;&amp;lt;=&amp;gt;?@[&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\\&lt;/span&gt;&lt;span style="color: #d07711;"&gt;]^_`{|}~'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;para &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&amp;quot;Hi&amp;quot;, there! How *are* you? All fine here.'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;para.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;translate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #a2a001;"&gt;str&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;maketrans&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;, punctuation))
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Hi there How are you All fine here'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;chars_to_delete &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #a2a001;"&gt;set&lt;/span&gt;&lt;span&gt;(punctuation) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;- &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'.!?'&lt;/span&gt;&lt;span&gt;))
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;para.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;translate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #a2a001;"&gt;str&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;maketrans&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;, chars_to_delete))
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Hi there! How are you? All fine here.'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 24 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-15/</guid></item><item><title>It's 2022 and we're (still) not deploying enough</title><link>https://smcleod.net/2022/08/its-2022-and-were-still-not-deploying-enough/</link><description>&lt;h2 id="were-still-not-deploying-enough"&gt;We&amp;rsquo;re (still) not deploying enough&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s 2022 and not deploying frequently enough is &lt;em&gt;still&lt;/em&gt; one of the most common causes of software failure.&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Tue, 23 Aug 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/08/its-2022-and-were-still-not-deploying-enough/</guid></item><item><title>The Moving AI Goalpost</title><link>https://jodavaho.io/posts/moving-ai-goalpost.html</link><description>&lt;p&gt;&lt;em&gt;This post is a work in progress&amp;hellip;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We have enough AI to explain conscioiusness now, and therefore to create an AI that feels &amp;ldquo;General&amp;rdquo;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI can generate words from sounds&lt;/li&gt;
&lt;li&gt;GPT is well known to generate narratives and conversations given rough priors&lt;/li&gt;
&lt;li&gt;Something like Dall E to generate mental imagery around those narratives, when required&lt;/li&gt;
&lt;li&gt;Constantly retrained by feeding what we hear (verbally) and what we see (after &amp;ldquo;object detection&amp;rdquo;) in a feedback loop, with all of our &amp;ldquo;story&amp;rdquo; as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The complication is the starting conditions. We are meant to believe that we are magic &amp;ldquo;conscious&amp;rdquo; creatures, even though centuries of contemplatives dispute this.&lt;/p&gt;
&lt;p&gt;Science is searching for something that doesn&amp;rsquo;t exist, and so the expectations of AI are too high. The above is enough.&lt;/p&gt;
&lt;h1 id="license"&gt;License&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://creativecommons.org/licenses/by-sa/4.0/deed.ast"&gt;CC BY-SA 4.0&lt;/a&gt;&lt;/p&gt;</description><author>jodavaho.io</author><pubDate>Tue, 23 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jodavaho.io/posts/moving-ai-goalpost.html</guid></item><item><title>The Evolution of Marginalia's crawling</title><link>https://www.marginalia.nu/log/63-marginalia-crawler/</link><description>&lt;p&gt;In the primordial days of Marginalia Search, it used a dynamic approach to crawling the Internet.&lt;/p&gt;
&lt;p&gt;It ran a number of crawler threads, 32 or 64 or some such, that fetched jobs from a director service, that grabbed them straight out of the URL database, these jobs were batches of 100 or so documents that needed to be crawled.&lt;/p&gt;
&lt;p&gt;Crawling was not planned ahead of time, but rather decided through a combination of how much of a website had been visited, and the quality score of that website determined where to go next. It also promoted crawling websites adjacent to high quality websites.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Tue, 23 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/63-marginalia-crawler/</guid></item><item><title>What's the big deal about key-value databases like FoundationDB and RocksDB?</title><link>http://notes.eatonphil.com/whats-the-big-deal-about-key-value-databases.html</link><description>&lt;p&gt;Let's assume you're familiar with basic SQL databases like PostgreSQL
and MySQL, and document databases like MongoDB and Elasticsearch. You
probably know Redis too.&lt;/p&gt;
&lt;p&gt;But you're hearing more and more about embedded key-value stores like
&lt;a href="http://rocksdb.org/"&gt;RocksDB&lt;/a&gt;,
&lt;a href="https://github.com/google/leveldb"&gt;LevelDB&lt;/a&gt;,
&lt;a href="https://github.com/cockroachdb/pebble"&gt;PebbleDB&lt;/a&gt;, and so on. And
you're hearing about distributed key-value databases like
&lt;a href="https://www.foundationdb.org/"&gt;FoundationDB&lt;/a&gt; and
&lt;a href="https://tikv.org/"&gt;TiKV&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What's the big deal? Aren't these just the equivalent of Redis or
Java's ConcurrentHashMap?&lt;/p&gt;
&lt;p&gt;Let's take a look.&lt;/p&gt;
&lt;h3 id="extensible-databases"&gt;Extensible databases&lt;/h3&gt;&lt;p&gt;Over the last 10 years or so (at least), databases have become more
extensible. MySQL has around &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/storage-engines.html"&gt;10 different open-source storage
engines&lt;/a&gt;. More
surely exist in the wild.&lt;/p&gt;
&lt;p&gt;Mongo supports &lt;a href="https://www.mongodb.com/docs/manual/core/storage-engines/"&gt;multiple storage
engines&lt;/a&gt;. Relatively
late, PostgreSQL version 12 added support for &lt;a href="https://www.postgresql.org/docs/current/tableam.html"&gt;pluggable storage
engines&lt;/a&gt;.&lt;/p&gt;
&lt;p class="note"&gt;
  &lt;a href="https://github.com/orioledb/orioledb"&gt;OrioleDB&lt;/a&gt;
  and &lt;a href="https://www.citusdata.com/blog/2021/03/06/citus-10-columnar-compression-for-postgres/"&gt;Citus
  10's columnar compression&lt;/a&gt; are two particularly interesting
  databases making use of PostgreSQL's pluggable storage engine. But
  since neither use an embedded key-value store, I won't talk about
  them more in this post.
&lt;/p&gt;&lt;p&gt;And so on.&lt;/p&gt;
&lt;h4 id="but-why?"&gt;But why?&lt;/h4&gt;&lt;p&gt;Swapping out storage engines allows you to tune the performance of
your database. It can allow you to swap out row-oriented storage for
column-oriented storage (useful for analytics workloads).&lt;/p&gt;
&lt;p&gt;It can allow you to swap B-Trees (traditional choice) for &lt;a href="http://www.benstopford.com/2015/02/14/log-structured-merge-trees/"&gt;LSM
Trees&lt;/a&gt;
(new hotness) as the underlying storage method (useful for optimizing
write-heavy workloads).&lt;/p&gt;
&lt;p&gt;And since some storage engines themselves are built on distributed
consensus (like &lt;a href="https://github.com/apple/foundationdb"&gt;FoundationDB&lt;/a&gt;
and &lt;a href="https://github.com/tikv/tikv"&gt;TiKV&lt;/a&gt;), it may even allow you to
turn a non-distributed database into a distributed database.&lt;/p&gt;
&lt;h3 id="mapping-sql-to-key-value-storage"&gt;Mapping SQL to key-value storage&lt;/h3&gt;&lt;p&gt;But how the heck do you turn SQL, row-oriented data, into key-value
data?&lt;/p&gt;
&lt;p&gt;CockroachDB is a SQL database built on &lt;a href="https://www.cockroachlabs.com/blog/pebble-rocksdb-kv-store/"&gt;RocksDB originally and now
their own LevelDB-inspired
database&lt;/a&gt;
called &lt;a href="https://github.com/cockroachdb/pebble"&gt;PebbleDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The reason I mention that here is because they maintain a great doc
about &lt;a href="https://github.com/cockroachdb/cockroach/blob/master/docs/tech-notes/encoding.md"&gt;their method of encoding rows to key-value
form&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To simplify that doc though you can imagine mapping each row
to a key-value form like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;TABLE_IDENTIFIER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="nx"&gt;_$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;PRIMARY_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="nx"&gt;_$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ROW_IDENTIFIER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ENCODED_VALUE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Embedded key-value stores almost always support efficient scanning of
rows by a key-prefix. This means that you can efficiently grab all rows
within a table by prefix-scanning on the table identifier. If you also
include a primary key value along with the table identifier prefix,
you get efficient primary key lookup.&lt;/p&gt;
&lt;p&gt;Even though the key space is flat.&lt;/p&gt;
&lt;p&gt;For the encoded value you can pick any encoding scheme; as
inefficient as JSON or as efficient as some binary scheme like
Protocol Buffers or Parquet.&lt;/p&gt;
&lt;p class="note"&gt;
  Thanks to &lt;a href="https://twitter.com/justinjaffray"&gt;Justin Jaffray&lt;/a&gt; for
  pointing me at the CockroachDB doc and confirming some of my thoughts
  on encoding strategies.
&lt;/p&gt;&lt;h4 id="tutorials"&gt;Tutorials&lt;/h4&gt;&lt;p&gt;I've written a couple of tutorials on building a database. They build on
top of embedded key-value stores. If you're interested in seeing
minimal code walkthroughs of how this process can work, check these
posts out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://notes.eatonphil.com/distributed-postgres.html"&gt;Let's build a distributed Postgres proof of concept&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://notes.eatonphil.com/documentdb.html"&gt;Writing a document database from scratch in Go: Lucene-like filters and indexes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="major-aspects-of-key-value-stores"&gt;Major aspects of key-value stores&lt;/h3&gt;&lt;p&gt;Now that you understand how a database can map to a key-value store,
let's take a look at the particular properties that distinguish all
these key-value stores from systems like Redis and Memcached.&lt;/p&gt;
&lt;h4 id="reliable-storage"&gt;Reliable storage&lt;/h4&gt;&lt;p&gt;Maybe the single most important thing a storage system does is actual
store data reliably. You can't just &lt;code&gt;open()&lt;/code&gt; and &lt;code&gt;write()&lt;/code&gt;. To quote
Dan Luu, &lt;a href="https://danluu.com/file-consistency/"&gt;files are
hard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Deferring storage correctness to a dedicated system means database
developers can worry about other aspects of database development.&lt;/p&gt;
&lt;h4 id="embeddable"&gt;Embeddable&lt;/h4&gt;&lt;p&gt;Along with reliable storage is the fact that the storage needs to run
in process. Redis, for example, is not embeddable. There are many
other things on top of the storage that need to happen in a high-level
database and RPC calls between processes for storage is an unnecessary
overhead.&lt;/p&gt;
&lt;h4 id="efficient-prefix-scans"&gt;Efficient prefix scans&lt;/h4&gt;&lt;p&gt;As mentioned above, support for scans is pretty important for how
indexes and namespaces (tables in SQL) get mapped to key-value
queries.&lt;/p&gt;
&lt;p&gt;You shouldn't need to look through all table rows in the flat key space to
find the rows for one table.&lt;/p&gt;
&lt;h4 id="additional-aspects"&gt;Additional aspects&lt;/h4&gt;&lt;p&gt;The above isn't a complete list. Different stores provide different
useful aspects like improved performance on certain workloads/in
certain environments, builtin transactions, and so on.&lt;/p&gt;
&lt;p&gt;And sometimes it's helpful just to have an embedded store in your
language rather than going through a foreign-function interface.&lt;/p&gt;
&lt;h3 id="survey-of-databases-built-on-embedded-key-value-stores"&gt;Survey of databases built on embedded key-value stores&lt;/h3&gt;&lt;p&gt;Lastly, let's take a look at a few databases that build on top of
embedded key-value stores.&lt;/p&gt;
&lt;p&gt;Note that some of them are not the primary version of the database
(e.g. MyRocks vs MySQL, MongoRocks vs Mongo). Some of them are the
primary version (e.g. CockroachDB, YugabyteDB).&lt;/p&gt;
&lt;h4 id="document-databases-built-on-key-value-stores"&gt;Document databases built on key-value stores&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/doc/percona-server-for-mongodb/3.4/mongorocks.html"&gt;MongoRocks&lt;/a&gt; (Mongo on RocksDB)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="sql-databases-built-on-key-value-stores"&gt;SQL databases built on key-value stores&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="http://myrocks.io/"&gt;MyRocks&lt;/a&gt; (MySQL on RocksDB)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cockroachlabs.com"&gt;CockroachDB&lt;/a&gt; (RocksDB originally, now their own PebbleDB)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.yugabyte.com/blog/how-we-built-a-high-performance-document-store-on-rocksdb/"&gt;YugabyteDB&lt;/a&gt; (on DocDB on RocksDB)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gridgain.com/resources/blog/apache-ignite-3-alpha-3-apache-calcite-raft-and-lsm-tree"&gt;Apache Ignite&lt;/a&gt; (Calcite on RocksDB)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="redis-compatible-databases-built-on-key-value-stores"&gt;Redis-compatible databases built on key-value stores&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://engineering.fb.com/2021/08/06/core-data/zippydb/"&gt;ZippyDB&lt;/a&gt; (Redis-compatible database on RocksDB)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://redis.com/blog/hood-redis-enterprise-flash-database-architecture/"&gt;Redis Enterprise Flash&lt;/a&gt; (Redis on RocksDB)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="other-databases-built-on-key-value-stores"&gt;Other databases built on key-value stores&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://thenewstack.io/instagram-supercharges-cassandra-pluggable-rocksdb-storage-engine/"&gt;Rocksandra&lt;/a&gt; (Cassandra on RocksDB)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Missing a database? Let me know!&lt;/p&gt;
&lt;h4 id="separately,-distributed-key-value-stores"&gt;Separately, distributed key-value stores&lt;/h4&gt;&lt;p&gt;There is a different kind of key-value store that is a standalone app
designed for distributed data. This list includes
&lt;a href="https://www.consul.io/"&gt;Consul&lt;/a&gt;,
&lt;a href="https://etcd.io/docs/v3.4/learning/why/"&gt;etcd&lt;/a&gt;, likely
&lt;a href="https://www.foundationdb.org/"&gt;FoundationDB&lt;/a&gt;, and likely
&lt;a href="https://engineering.fb.com/2021/08/06/core-data/zippydb/"&gt;ZippyDB&lt;/a&gt;. (There's
a nice comparison table about some of these databases on the etcd
page).&lt;/p&gt;
&lt;p&gt;These systems are designed to be used sort of like Redis except for
that they are persistant and reliable stores. They are designed to
always be up and always correct. For that reason they form the data
storage backbone of core infrastructure like Kubernetes.&lt;/p&gt;
&lt;p&gt;It is possibly how &lt;a href="https://www.snowflake.com/blog/how-foundationdb-powers-snowflake-metadata-forward/"&gt;Snowflake uses
FoundationDB&lt;/a&gt;
but I'm not 100% sure.&lt;/p&gt;
&lt;p&gt;TiKV is not an embedded key-value database but it's not being used the
same way etcd/Consul are as far as I can tell. It forms the backbone
of &lt;a href="https://en.pingcap.com/"&gt;TiDB&lt;/a&gt;, an HTAP (hybrid OLAP/OLTP) SQL
database.&lt;/p&gt;
&lt;p&gt;Maybe FoundationDB and TiKV deserve their own new category.&lt;/p&gt;
&lt;p&gt;But in general these databases have an RPC API that you communicate
with over TCP. They are not generally embedded. You manage their
process(es) separately.&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;&lt;p&gt;So in this post we saw that databases are extensible. Storage engines
are often swappable. Dedicated embedded key-value stores allow
database developers to hand off data storage to a dedicated
library. Different key-value stores have different performance
characteristics that help developers and operators tune a database for
their workload.&lt;/p&gt;
&lt;p&gt;Embedded key-value stores are a great foundation for all kinds of
databases; SQL databases like CockroachDB, document databases like
Mongo, wide-store databases like Cassandra, and caching databases like
ZippyDB or Redis Enterprise Flash.&lt;/p&gt;
&lt;p&gt;This is a complex topic with many, many variations of
systems. Hopefully this was a useful introduction.&lt;/p&gt;
&lt;p&gt;Overall if you're not a database developer and you're not running
databases at a massive scale, you can probably ignore the details of
the storage layer.&lt;/p&gt;
&lt;p&gt;Did I get something wrong? Or miss something important? Let me
know. :)&lt;/p&gt;
&lt;h3 id="corrections"&gt;Corrections&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;An earlier version of this post suggested that FoundationDB was
embedded. It is not. Thanks &lt;a href="https://lobste.rs/s/avljlh/what_s_big_deal_about_embedded_key_value#c_rx0oid"&gt;adaszko on Lobsters for
correcting&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An earlier version of this post suggested that TiKV was embedded. It is not. Thanks &lt;a href="https://news.ycombinator.com/user?id=eis"&gt;eis on Hacker News&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;What's the big deal about embedded key-value databases like FoundationDB ands RocksDB?&lt;br /&gt;&lt;br /&gt;I wrote a new blog post that might give a little context. :)&lt;a href="https://t.co/kNFM1hVGx6"&gt;https://t.co/kNFM1hVGx6&lt;/a&gt; &lt;a href="https://t.co/H4SouStZHk"&gt;pic.twitter.com/H4SouStZHk&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1562106582544039937?ref_src=twsrc%5Etfw"&gt;August 23, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Tue, 23 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/whats-the-big-deal-about-key-value-databases.html</guid></item><item><title>Cost of a integer cast in Go</title><link>https://boyter.org/posts/cost-of-integer-cast-in-go/</link><description>&lt;p&gt;Recently have been doing interviews at work for Go developers.&lt;/p&gt;
&lt;p&gt;The filter for this is a simple review exercise. We present a small chunk of code and ask them to review it over 15 minutes pointing out any issues they see. The idea is to respect their and our time. It works pretty well and we can determine how much experience someone has by their ability to pick up the obvious vs subtle bugs.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Mon, 22 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/cost-of-integer-cast-in-go/</guid></item><item><title>The Surprisingly High Table Stakes of Modern Blogs</title><link>https://www.swyx.io/the-surprisingly-high-table-stakes-of-modern-blogs</link><description>&lt;p&gt;Bottom Line Up Front: You are probably underestimating how much goes into blogging technology these days.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sun, 21 Aug 2022 23:21:53 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/the-surprisingly-high-table-stakes-of-modern-blogs</guid></item><item><title>How to write a Python Twitter Unfollow Script in 2022</title><link>https://www.swyx.io/how-to-write-a-python-twitter-unfollow-script-in-2022</link><description>&lt;p&gt;The Twitter API has changed (from v1 to v2), and Python has gone from 2 to 3, and Google is still serving up loads of outdated results.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sun, 21 Aug 2022 07:28:59 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/how-to-write-a-python-twitter-unfollow-script-in-2022</guid></item><item><title>SQLite has pretty limited builtin functions</title><link>http://notes.eatonphil.com/2022-08-21-sqlite-limited-builtin-functions.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-08-21-sqlite-limited-builtin-functions.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 21 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/2022-08-21-sqlite-limited-builtin-functions.html</guid></item><item><title>2022–08–21: Sound on Pinephone Pro</title><link>https://xnux.eu/log/#074</link><author>megi's PinePhone Development Log</author><pubDate>Sun, 21 Aug 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#074</guid></item><item><title>Writing my first Security blogpost</title><link>https://www.swyx.io/writing-my-first-security-blogpost</link><description>&lt;p&gt;Today's fun emergency at work was a first - writing a security postmortem for a breach of an &lt;em&gt;open source user&lt;/em&gt; (aka not a breach of us, which seems the norm).&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Fri, 19 Aug 2022 05:51:52 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/writing-my-first-security-blogpost</guid></item><item><title>Marginaliacoin, and hidden forums</title><link>https://www.marginalia.nu/log/62-marginaliacoin/</link><description>&lt;p&gt;I discovered someone has made a cryptocurrency called &amp;ldquo;Memex Marginalia Inu&amp;rdquo;. It appears to have been created February 23, which is around when the entry &amp;ldquo;I Have No Capslock And I Must Scream&amp;rdquo; went absurdly viral to the point where Elon Musk tweeted a link to it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.marginalia.nu/log/48-i-have-no-capslock.gmi"&gt;I Have No Capslock&amp;hellip;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mr Musk&amp;rsquo;s twitter orbit is exceptionally strange. The tweet was followed by a deluge of bizarre activity, strange emails with calls about stonk canine lunar expeditions, and apparently also a cryptocurrency land-grab of sorts. I can&amp;rsquo;t claim to understand why, but many of the emails got after the tweet were on the theme &amp;ldquo;what does this mean?&amp;rdquo;, almost as though Elon&amp;rsquo;s tweet was some sort of prophetic omen.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Thu, 18 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/62-marginaliacoin/</guid></item><item><title>Vim prank: alias vim='vim -y'</title><link>https://learnbyexample.github.io/mini/vim-prank/</link><description>&lt;p align="center"&gt;&lt;img alt="Vim Prank" src="/images/vim_prank.png" /&gt;&lt;/p&gt;
&lt;p align="center"&gt;&lt;i&gt;Poster created using &lt;a href="https://www.canva.com/"&gt;Canva&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;While going through &lt;a href="https://vimhelp.org/starting.txt.html#vim-arguments"&gt;:h vim-arguments&lt;/a&gt; for my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; ebook, I came across the &lt;code&gt;-y&lt;/code&gt; option:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Easy mode. Implied for &lt;code&gt;evim&lt;/code&gt; and &lt;code&gt;eview&lt;/code&gt;. Starts with &lt;code&gt;'insertmode'&lt;/code&gt; set and behaves like a click-and-type editor. This sources the script $VIMRUNTIME/evim.vim. Mappings are set up to work like most click-and-type editors, see &lt;code&gt;evim-keys&lt;/code&gt;. The GUI is started when available.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It was so weird to use. Copy and paste works with &lt;code&gt;Ctrl+c&lt;/code&gt; and &lt;code&gt;Ctrl+v&lt;/code&gt; respectively. Text can be selected with mouse and typing new text overwrites this selected portion. &lt;code&gt;Esc&lt;/code&gt; key doesn't work (gasp!), so I couldn't quit until I used the window buttons. Later I tried and found that &lt;code&gt;Ctrl+o&lt;/code&gt; works, which would then allow you to use &lt;code&gt;:q&lt;/code&gt; as usual.&lt;/p&gt;
&lt;p&gt;So, if you want to prank a Vim user:&lt;/p&gt;
&lt;pre class="language-bash " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-bash"&gt;&lt;span style="color: #b39f04;"&gt;alias &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;vim&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'vim -y'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; I didn't expect such a good response on &lt;a href="https://www.reddit.com/r/vim/comments/rxedpj/vim_prank_alias_vimvim_y/"&gt;/r/vim/&lt;/a&gt; and &lt;a href="https://twitter.com/learn_byexample/status/1478976141650059264"&gt;twitter&lt;/a&gt; for this &amp;quot;easy&amp;quot; feature. So, decided to write this mini blog post as well. Also, I got to know a few more ways to escape this madness from the /r/vim/ sub:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One hint: If you want to go to Normal mode to be able to type a sequence of commands, use &lt;code&gt;CTRL-L&lt;/code&gt;. &lt;a href="https://vimhelp.org/starting.txt.html#evim-keys"&gt;https://vimhelp.org/starting.txt.html#evim-keys&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Use &lt;code&gt;&amp;lt;c-\&amp;gt;&amp;lt;c-n&amp;gt;&lt;/code&gt; See &lt;code&gt;:h CTRL-\_CTRL-N&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So, this post reached front page on &lt;a href="https://news.ycombinator.com/item?id=29837543"&gt;Hacker News&lt;/a&gt;! Plenty of interesting comments and got to know about &lt;a href="https://github.com/tombh/novim-mode"&gt;novim-mode&lt;/a&gt; plugin (which aims to make Vim behave more like a 'normal' editor).&lt;/p&gt;
&lt;p&gt;I also found &lt;a href="https://www.reddit.com/r/vim/comments/5102o5/an_evil_trick_to_prank_vimsters/"&gt;an old discussion on /r/vim/&lt;/a&gt; discussing ways to trick a Vim user.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 17 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/mini/vim-prank/</guid></item><item><title>GNU BRE/ERE cheatsheet and differences between grep, sed and awk</title><link>https://learnbyexample.github.io/gnu-bre-ere-cheatsheet/</link><description>&lt;p align="center"&gt;&lt;img alt="GNU BRE/ERE cheatsheet" src="/images/bre_ere_cheatsheet.png" /&gt;&lt;/p&gt;
&lt;p align="center"&gt;&lt;i&gt;Poster created using &lt;a href="https://www.canva.com/"&gt;Canva&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;This post covers &lt;strong&gt;Basic Regular Expressions&lt;/strong&gt; (BRE) and &lt;strong&gt;Extended Regular Expressions&lt;/strong&gt; (ERE) syntax supported by GNU &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt;. You'll also learn the differences between these tools — for example, &lt;code&gt;awk&lt;/code&gt; doesn't support backreferences within regexp definition (i.e. the search portion).&lt;/p&gt;
&lt;span id="continue-reading"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h2 id="bre-and-ere"&gt;BRE and ERE&lt;a class="zola-anchor" href="#bre-and-ere"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; From &lt;a href="https://www.gnu.org/software/grep/manual/grep.html#Basic-vs-Extended"&gt;GNU grep manual&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In basic regular expressions the meta-characters &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;{&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt;, and &lt;code&gt;)&lt;/code&gt; lose their special meaning; instead use the backslashed versions &lt;code&gt;\?&lt;/code&gt;, &lt;code&gt;\+&lt;/code&gt;, &lt;code&gt;\{&lt;/code&gt;, &lt;code&gt;\|&lt;/code&gt;, &lt;code&gt;\(&lt;/code&gt;, and &lt;code&gt;\)&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt; support BRE by default and enables ERE when &lt;code&gt;-E&lt;/code&gt; option is used. &lt;code&gt;awk&lt;/code&gt; supports only ERE. Assume ERE for descriptions in this post unless otherwise mentioned.&lt;/p&gt;
&lt;p&gt;This post is intended as a reference for BRE/ERE flavor of regular expressions. For a more detailed explanation with examples and exercises, see these chapters from &lt;a href="https://learnbyexample.github.io/books/"&gt;my ebooks&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/learn_gnugrep_ripgrep/breere-regular-expressions.html"&gt;grep BRE/ERE Regular Expressions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/learn_gnused/breere-regular-expressions.html"&gt;sed BRE/ERE Regular Expressions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.github.io/learn_gnuawk/regular-expressions.html"&gt;awk Regular Expressions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 id="anchors"&gt;Anchors&lt;a class="zola-anchor" href="#anchors"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;^&lt;/code&gt;&lt;/td&gt;&lt;td&gt;restricts the match to the start of the string&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;$&lt;/code&gt;&lt;/td&gt;&lt;td&gt;restricts the match to the end of the string&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\&amp;lt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;restricts the match to the start of word&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;restricts the match to the end of word&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;-x&lt;/code&gt; cli option in &lt;code&gt;grep&lt;/code&gt; is equivalent to &lt;code&gt;^pattern$&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Word characters include alphabets, digits and underscore. Here's some more alternate ways to specify word anchors:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;restricts the match to the start/end of words, applicable for &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\y&lt;/code&gt;&lt;/td&gt;&lt;td&gt;restricts the match to the start/end of words, applicable for &lt;code&gt;awk&lt;/code&gt; (&lt;code&gt;\b&lt;/code&gt; means backspace)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\B&lt;/code&gt;&lt;/td&gt;&lt;td&gt;matches wherever &lt;code&gt;\b&lt;/code&gt; (or &lt;code&gt;\y&lt;/code&gt;) doesn't match&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; also supports &lt;code&gt;-w&lt;/code&gt; cli option. It is equivalent to &lt;code&gt;(?&amp;lt;!\w)pattern(?!\w)&lt;/code&gt;. The three different ways to specify word anchors are not exactly equivalent though, see &lt;a href="https://learnbyexample.github.io/learn_gnugrep_ripgrep/gotchas-and-tricks.html#word-boundary-differences"&gt;Word boundary differences&lt;/a&gt; section from my book for details and examples.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="alternation-and-grouping"&gt;Alternation and Grouping&lt;a class="zola-anchor" href="#alternation-and-grouping"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pat1|pat2|pat3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match &lt;code&gt;pat1&lt;/code&gt; or &lt;code&gt;pat2&lt;/code&gt; or &lt;code&gt;pat3&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;use &lt;code&gt;\|&lt;/code&gt; in BRE mode&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;group pattern(s), &lt;code&gt;a(b|c)d&lt;/code&gt; is same as &lt;code&gt;abd|acd&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;use &lt;code&gt;\(\)&lt;/code&gt; in BRE mode&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The alternative patterns can have their own independent anchors. Alternative which matches earliest in the input gets precedence. Longest matching portion wins if multiple alternatives start from the same location (irrespective of the order of alternatives). In case of a tie with same lengths, leftmost alternative wins (see &lt;a href="https://stackoverflow.com/a/39752929/4082052"&gt;stackoverflow: Non greedy matching in sed&lt;/a&gt; for a practical use case).&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="escaping-metacharacters"&gt;Escaping metacharacters&lt;a class="zola-anchor" href="#escaping-metacharacters"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\&lt;/code&gt;&lt;/td&gt;&lt;td&gt;prefix metacharacters with &lt;code&gt;\&lt;/code&gt; to match them literally&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\\&lt;/code&gt;&lt;/td&gt;&lt;td&gt;to match &lt;code&gt;\&lt;/code&gt; literally&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt;, switching between ERE and BRE can reduce the number of escapes needed for some cases. For fixed string matching, &lt;code&gt;grep&lt;/code&gt; has &lt;code&gt;-F&lt;/code&gt; option and &lt;code&gt;awk&lt;/code&gt; has string comparison operators (whole string) and the &lt;code&gt;index&lt;/code&gt; function (partial string).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sed&lt;/code&gt; requires both &lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt; characters to be escaped (in ERE mode), whereas &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt; don't require &lt;code&gt;)&lt;/code&gt; to be escaped.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sed&lt;/code&gt; requires &lt;code&gt;{&lt;/code&gt; to be escaped (in ERE mode) even if it isn't part of a valid quantifier syntax, whereas &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt; don't require escaping. For example, you'd need &lt;code&gt;\{a}&lt;/code&gt; in &lt;code&gt;sed&lt;/code&gt; whereas &lt;code&gt;{a}&lt;/code&gt; is enough for the other two.&lt;/li&gt;
&lt;li&gt;In BRE mode, &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt; don't require &lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; to be escaped if they are used away from their customary positions.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 id="dot-metacharacter-and-quantifiers"&gt;Dot metacharacter and Quantifiers&lt;a class="zola-anchor" href="#dot-metacharacter-and-quantifiers"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match any character, including the newline character&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;1&lt;/code&gt; times&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;use &lt;code&gt;\?&lt;/code&gt; in BRE mode&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match &lt;code&gt;0&lt;/code&gt; or more times&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match &lt;code&gt;1&lt;/code&gt; or more times&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;use &lt;code&gt;\+&lt;/code&gt; in BRE mode&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{m,n}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match &lt;code&gt;m&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt; times&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{m,}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match at least &lt;code&gt;m&lt;/code&gt; times&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{,n}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match up to &lt;code&gt;n&lt;/code&gt; times (including &lt;code&gt;0&lt;/code&gt; times)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{n}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match exactly &lt;code&gt;n&lt;/code&gt; times&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;use &lt;code&gt;\{\}&lt;/code&gt; in BRE mode&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pat1.*pat2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;any number of characters between &lt;code&gt;pat1&lt;/code&gt; and &lt;code&gt;pat2&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pat1.*pat2|pat2.*pat1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match both &lt;code&gt;pat1&lt;/code&gt; and &lt;code&gt;pat2&lt;/code&gt; in any order&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Precedence rule is &lt;em&gt;longest match wins&lt;/em&gt;, which is mostly similar but not exactly same as greedy quantifiers. For example, with &lt;code&gt;foo123312baz&lt;/code&gt; as input string, &lt;code&gt;o[123]+(12baz)?&lt;/code&gt; will match &lt;code&gt;o123312baz&lt;/code&gt; with these tools, whereas it will match &lt;code&gt;o123312&lt;/code&gt; with greedy quantifiers.&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id="character-class"&gt;Character class&lt;a class="zola-anchor" href="#character-class"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[set123]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match any of these characters once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[^set123]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match except any of these characters once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[3-7AM-X]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;range of characters from &lt;code&gt;3&lt;/code&gt; to &lt;code&gt;7&lt;/code&gt;, &lt;code&gt;A&lt;/code&gt;, another range from &lt;code&gt;M&lt;/code&gt; to &lt;code&gt;X&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[.&lt;/code&gt;&lt;/td&gt;&lt;td&gt;open collating symbol&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;.]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;close collating symbol&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;open equivalence class&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;=]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;close equivalence class&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Specific placement will help to match character class metacharacters literally.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[a-z-]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;-&lt;/code&gt; should be first/last character to match literally&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[+^]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;^&lt;/code&gt; shouldn't be first character&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[]=]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;]&lt;/code&gt; should be first character (second if &lt;code&gt;^&lt;/code&gt; is used to invert the set)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;\&lt;/code&gt; isn't special within character class in &lt;code&gt;grep&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\&lt;/code&gt; can be used to escape character class metacharacters in &lt;code&gt;awk&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some commonly used character sets have predefined escape sequences:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\w&lt;/code&gt;&lt;/td&gt;&lt;td&gt;similar to &lt;code&gt;[a-zA-Z0-9_]&lt;/code&gt; for matching word characters&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;similar to &lt;code&gt;[ \t\n\r\f\v]&lt;/code&gt; for matching whitespace characters&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\W&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match non-word characters&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\S&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match non-whitespace characters&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;Undefined escape sequences will be treated as the character it escapes. For example, &lt;code&gt;\e&lt;/code&gt; will match &lt;code&gt;e&lt;/code&gt; (not &lt;code&gt;\&lt;/code&gt; and &lt;code&gt;e&lt;/code&gt;).
&lt;ul&gt;
&lt;li&gt;in addition, &lt;code&gt;awk&lt;/code&gt; gives a &amp;quot;not a known regexp operator&amp;quot; warning.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The above escape sequences &lt;em&gt;cannot&lt;/em&gt; be used inside character classes and behavior varies between the tools.
&lt;ul&gt;
&lt;li&gt;For example, using &lt;code&gt;[\w]&lt;/code&gt; will match &lt;code&gt;\&lt;/code&gt; or &lt;code&gt;w&lt;/code&gt; characters in &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt; whereas it will match only &lt;code&gt;w&lt;/code&gt; in &lt;code&gt;awk&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;These escape sequences are also locale aware, for example &lt;code&gt;αλεπού&lt;/code&gt; and &lt;code&gt;\u2028&lt;/code&gt; (line separator) will be considered as word and whitespace characters respectively in appropriate locales.&lt;/li&gt;
&lt;li&gt;These tools do &lt;em&gt;not&lt;/em&gt; support &lt;code&gt;\d&lt;/code&gt; and &lt;code&gt;\D&lt;/code&gt;, commonly featured in other regexp implementations for digits and non-digits.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 id="escape-sequences"&gt;Escape sequences&lt;a class="zola-anchor" href="#escape-sequences"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section is applicable only for &lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt; unless otherwise specified and can be used within character classes too. See also &lt;a href="https://ascii.cl/"&gt;ASCII Codes Table Standard characters&lt;/a&gt;.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Escape sequence&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;alert&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;backspace in &lt;code&gt;awk&lt;/code&gt;, word boundary in &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;\b&lt;/code&gt; inside a character class in &lt;code&gt;sed&lt;/code&gt; will act as a backspace&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;formfeed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;newline&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\r&lt;/code&gt;&lt;/td&gt;&lt;td&gt;carriage return&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\t&lt;/code&gt;&lt;/td&gt;&lt;td&gt;horizontal tab&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\v&lt;/code&gt;&lt;/td&gt;&lt;td&gt;vertical tab&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\cx&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CONTROL-x in &lt;code&gt;sed&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;You can also represent ASCII characters using their codepoint values.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Escape sequence&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\xNN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;hexadecimal digits&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\NNN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;octal digits in &lt;code&gt;awk&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\oNNN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;octal digits in &lt;code&gt;sed&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\dNNN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;decimal digits in &lt;code&gt;sed&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;In search section, a metacharacter specified by escape sequences will still act as the metacharacter. For example, &lt;code&gt;/\x5eco/&lt;/code&gt; will match &lt;code&gt;co&lt;/code&gt; only at the start of the string.&lt;/li&gt;
&lt;li&gt;In replacement section,
&lt;ul&gt;
&lt;li&gt;escape sequences in &lt;code&gt;sed&lt;/code&gt; produces literal character. For example, &lt;code&gt;s/.*/&amp;quot;\x26&amp;quot;/&lt;/code&gt; will have &lt;code&gt;&amp;quot;&amp;amp;&amp;quot;&lt;/code&gt; as the replacement value.&lt;/li&gt;
&lt;li&gt;escape sequences in &lt;code&gt;awk&lt;/code&gt; is treated as metacharacter. For example, &lt;code&gt;sub(/.*/, &amp;quot;[&amp;amp;]&amp;quot;)&lt;/code&gt; and &lt;code&gt;sub(/.*/, &amp;quot;[\x26]&amp;quot;)&lt;/code&gt; are equivalent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Ways to use escape sequences with &lt;code&gt;grep&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/manual/bash.html#ANSI_002dC-Quoting"&gt;ANSI-C Quoting&lt;/a&gt; — for example, &lt;code&gt;$'a\tb'&lt;/code&gt; will match &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; with a tab in between.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-P&lt;/code&gt; option, see my chapter on &lt;a href="https://learnbyexample.github.io/learn_gnugrep_ripgrep/perl-compatible-regular-expressions.html"&gt;Perl Compatible Regular Expressions&lt;/a&gt; for more details.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 id="named-character-sets"&gt;Named character sets&lt;a class="zola-anchor" href="#named-character-sets"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The below table lists named sets and their equivalent character class in ASCII encoding. These can be used inside character classes only. For example, &lt;code&gt;[[:digit:]]&lt;/code&gt; is same as &lt;code&gt;[0-9]&lt;/code&gt; and &lt;code&gt;[[:alnum:]_]&lt;/code&gt; is equivalent to &lt;code&gt;\w&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Named set&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:digit:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[0-9]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:lower:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[a-z]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:upper:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[A-Z]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:alpha:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[a-zA-Z]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:alnum:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[0-9a-zA-Z]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:xdigit:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[0-9a-fA-F]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:cntrl:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;control characters — first 32 ASCII characters and 127th (DEL)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:punct:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;all the punctuation characters&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:graph:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[:alnum:]&lt;/code&gt; and &lt;code&gt;[:punct:]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:print:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[:alnum:]&lt;/code&gt;, &lt;code&gt;[:punct:]&lt;/code&gt; and space&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:blank:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;space and tab characters&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[:space:]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;whitespace characters, same as &lt;code&gt;\s&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; From &lt;a href="https://www.gnu.org/software/grep/manual/grep.html#Character-Classes-and-Bracket-Expressions"&gt;grep manual&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Their interpretation depends on the &lt;code&gt;LC_CTYPE&lt;/code&gt; locale; for example, &lt;code&gt;[[:alnum:]]&lt;/code&gt; means the character class of numbers and letters in the current locale.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
&lt;h2 id="backreferences"&gt;Backreferences&lt;a class="zola-anchor" href="#backreferences"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;backreference, gives matched portion of Nth capture group&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;possible values: &lt;code&gt;\1&lt;/code&gt;, &lt;code&gt;\2&lt;/code&gt; up to &lt;code&gt;\9&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;represents entire matched string in the replacement section&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\0&lt;/code&gt;&lt;/td&gt;&lt;td&gt;equivalent to &lt;code&gt;&amp;amp;&lt;/code&gt; in &lt;code&gt;sed&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Notes for &lt;code&gt;awk&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;backreferences can be used only in replacement section, not allowed in search section.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sub&lt;/code&gt; and &lt;code&gt;gsub&lt;/code&gt; functions allow only the &lt;code&gt;&amp;amp;&lt;/code&gt; backreference.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gensub&lt;/code&gt; function allows &lt;code&gt;\N&lt;/code&gt; form of backreference as well.
&lt;ul&gt;
&lt;li&gt;but need to use &lt;code&gt;\\0&lt;/code&gt;, &lt;code&gt;\\1&lt;/code&gt;, &lt;code&gt;\\2&lt;/code&gt; etc since they are specified using string syntax.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 id="sed-flags"&gt;sed flags&lt;a class="zola-anchor" href="#sed-flags"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section discusses flags (also known as modifiers) that change the regexp behavior. When used with regexp addressing:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Flag&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;I&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match case insensitively&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;When used with substitution command:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Flag&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;i&lt;/code&gt; or &lt;code&gt;I&lt;/code&gt;&lt;/td&gt;&lt;td&gt;match case insensitively&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;g&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replace all occurrences instead of just the first match&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a number will cause only the &lt;em&gt;N&lt;/em&gt;th match to be replaced&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ng&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replace from &lt;em&gt;N&lt;/em&gt;th match to the end&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;m&lt;/code&gt; or &lt;code&gt;M&lt;/code&gt;&lt;/td&gt;&lt;td&gt;multiline mode&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.&lt;/code&gt; will not match the newline character&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; will match every line's start and end locations (line separator is &lt;code&gt;\n&lt;/code&gt; by default and NUL when &lt;code&gt;-z&lt;/code&gt; option is used)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\`&lt;/code&gt;&lt;/td&gt;&lt;td&gt;always match the start of string irrespective of multiline mode&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\'&lt;/code&gt;&lt;/td&gt;&lt;td&gt;always match the end of string irrespective of multiline mode&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Flags are not supported by &lt;code&gt;grep&lt;/code&gt; or &lt;code&gt;awk&lt;/code&gt;. But these equivalent/alternative options can be used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; cli option in &lt;code&gt;grep&lt;/code&gt; and setting &lt;code&gt;IGNORECASE&lt;/code&gt; to non-zero value in &lt;code&gt;awk&lt;/code&gt; will match case insensitively.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tolower&lt;/code&gt; or &lt;code&gt;toupper&lt;/code&gt; functions can be used in &lt;code&gt;awk&lt;/code&gt; to convert input to single case.&lt;/li&gt;
&lt;li&gt;you can also use character classes for small strings, for example &lt;code&gt;[cC][aA][tT]&lt;/code&gt; will match &lt;code&gt;cat&lt;/code&gt; case insensitively.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sub&lt;/code&gt; function in &lt;code&gt;awk&lt;/code&gt; replaces only the first matching occurrence and &lt;code&gt;gsub&lt;/code&gt; function is equivalent to using the &lt;code&gt;g&lt;/code&gt; flag.&lt;/li&gt;
&lt;li&gt;third argument of &lt;code&gt;gensub&lt;/code&gt; function in &lt;code&gt;awk&lt;/code&gt; supports replacing only the &lt;em&gt;N&lt;/em&gt;th match as well as the &lt;code&gt;g&lt;/code&gt; flag.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The behavior of &lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt; differs for &lt;em&gt;N&lt;/em&gt;th match if the pattern can match empty string:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a,,c,d,,f' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; sed &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'s/[^,]*/b/2'
&lt;/span&gt;&lt;span&gt;a,b,c,d,,f
&lt;/span&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a,,c,d,,f' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; sed &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'s/[^,]*/e/5'
&lt;/span&gt;&lt;span&gt;a,,c,d,e,f
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a,,c,d,,f' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'{print gensub(/[^,]*/, &amp;quot;b&amp;quot;, 2)}'
&lt;/span&gt;&lt;span&gt;ab,,c,d,,f
&lt;/span&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a,,c,d,,f' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'{print gensub(/[^,]*/, &amp;quot;e&amp;quot;, 5)}'
&lt;/span&gt;&lt;span&gt;a,,ce,d,,f
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;h2 id="sed-case-conversion"&gt;sed case conversion&lt;a class="zola-anchor" href="#sed-case-conversion"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Escape sequence&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\E&lt;/code&gt;&lt;/td&gt;&lt;td&gt;indicates end of case conversion in replacement section&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\l&lt;/code&gt;&lt;/td&gt;&lt;td&gt;convert next character to lowercase&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\u&lt;/code&gt;&lt;/td&gt;&lt;td&gt;convert next character to uppercase&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\L&lt;/code&gt;&lt;/td&gt;&lt;td&gt;convert following characters to lowercase, stops if &lt;code&gt;\U&lt;/code&gt; or &lt;code&gt;\E&lt;/code&gt; is found&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\U&lt;/code&gt;&lt;/td&gt;&lt;td&gt;convert following characters to uppercase, stops if &lt;code&gt;\L&lt;/code&gt; or &lt;code&gt;\E&lt;/code&gt; is found&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;h2 id="sed-delimiters"&gt;sed delimiters&lt;a class="zola-anchor" href="#sed-delimiters"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt; is idiomatically used as the delimiter.&lt;/li&gt;
&lt;li&gt;Any character except &lt;code&gt;\&lt;/code&gt; and newline character can also be used. For example: &lt;code&gt;s#/home/learnbyexample/#~/#&lt;/code&gt; is same as &lt;code&gt;s/\/home\/learnbyexample\//~\//&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For regexp addressing, the first delimiter has to be escaped. For example: &lt;code&gt;\;/foo/bar/;p&lt;/code&gt; is same as &lt;code&gt;/foo\/bar\//p&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>learnbyexample</author><pubDate>Wed, 17 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/gnu-bre-ere-cheatsheet/</guid></item><item><title>Vim tip 13: repeat last change</title><link>https://learnbyexample.github.io/tips/vim-tip-13/</link><description>&lt;p&gt;It is way too easy to repeat the last change you made:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;.&lt;/kbd&gt; the Normal mode &lt;strong&gt;dot&lt;/strong&gt; command repeats the last change
&lt;ul&gt;
&lt;li&gt;you can also use a number prefix to override the count of the last change&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if the last change was &lt;kbd&gt;2dd&lt;/kbd&gt; (delete current line and the line below), dot key will repeat &lt;code&gt;2dd&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;using &lt;kbd&gt;3.&lt;/kbd&gt; will mean &lt;code&gt;3dd&lt;/code&gt; and not &lt;code&gt;6dd&lt;/code&gt;, since the count prefix replaces the earlier number&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;if the last change was &lt;kbd&gt;5x&lt;/kbd&gt; (delete current character and four characters to the right), dot key will repeat &lt;code&gt;5x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;if the last change was &lt;kbd&gt;C123&amp;lt;Esc&amp;gt;&lt;/kbd&gt; and dot key is pressed, it will clear from the current character to the end of the line, insert &lt;code&gt;123&lt;/code&gt; and go back to Normal mode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From &lt;a href="https://vimhelp.org/usr_04.txt.html#04.3"&gt;:h 4.3&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;kbd&gt;.&lt;/kbd&gt; command works for all changes you make, except for &lt;kbd&gt;u&lt;/kbd&gt; (undo), &lt;kbd&gt;CTRL-R&lt;/kbd&gt; (redo) and commands that start with a colon (&lt;code&gt;:&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/repeat.txt.html"&gt;:h repeat.txt&lt;/a&gt; for complex repeats, using Vim scripts, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 16 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-13/</guid></item><item><title>2022–08–14: USB recovery/hacking tool for Pinephone Pro</title><link>https://xnux.eu/log/#073</link><author>megi's PinePhone Development Log</author><pubDate>Sun, 14 Aug 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#073</guid></item><item><title>Rest in Peace, Optane</title><link>https://specbranch.com/posts/rip-optane/</link><description>&lt;p&gt;Intel's Optane memory modules launched with a lot of fanfare in 2015, and were recently
discontinued, in 2022, with similar fanfare.  It was a sad day for me, a lover of
abstraction-breaking technologies, but it was forseeable and understandable.&lt;/p&gt;
&lt;p&gt;At the time of Optane's launch, a lot of us were excited about the idea of having a new storage
tier, sitting between DRAM and flash.  It was announced as having DRAM endurance and speed with
the persistence and size of flash.  It was a futuristic memory technology, but the technology of
the future met the full force of Wright's Law.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Fri, 12 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/rip-optane/</guid></item><item><title>Native-GUI distributed system in a tweet</title><link>https://blog.metaobject.com/2022/08/native-gui-distributed-system-in-tweet.html</link><description>If I've been a bit quiet recently it's not due to lack of progress, but rather the very opposite:  so much progress in &lt;a href="http://objective.st"&gt;Objective-S&lt;/a&gt; land hat my head is spinning and I am having a
hard time both processing it all and seeing where it goes.&lt;p&gt;



&lt;p&gt;

But sometimes you need to pause, reflect, and show your work, in whatever intermediate state 
it currently is.  So without further ado, here is the distributed system, with GUI, in a tweet:&lt;p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;#!env stui&lt;br /&gt;scheme:s3 ← ref:http://defiant.local:2345/ asScheme&lt;br /&gt;text ← #NSTextField{ #stringValue:'',#frame:(10@45 extent:180@24) }.&lt;br /&gt;window ← #NSWindow{ #frame:(300@300 extent:200@105),#title:'S3', #views:#[text]}.&lt;br /&gt;text → ref:s3:bucket1/msg.txt.&lt;br /&gt;app runFromCLI:window.&lt;/p&gt;&amp;mdash; Marcel Weiher 🇪🇺 (@mpweiher) &lt;a href="https://twitter.com/mpweiher/status/1556975759524249600?ref_src=twsrc%5Etfw"&gt;August 9, 2022&lt;/a&gt;&lt;/blockquote&gt; 

&lt;p&gt;

It pops up a window with a text field, and stores whatever the user enters in an S3 bucket.
It continues to do this until the user closes the window, at which point the program exits.&lt;p&gt;

Of course, it's not &lt;em&gt;much&lt;/em&gt; of a distributed system, particularly because it doesn't 
actually include the code for the S3 simulator.&lt;p&gt;

Anyway, despite fitting in a tweet, the Objective-S script is actually not &lt;a href="https://en.wikipedia.org/wiki/Code_golf"&gt;code golf&lt;/a&gt;, although it may appear as such to someone not familiar with Objective-S.&lt;p&gt;

Instead, it is a straightforward definition and composition of the elements required:&lt;p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;a href="https://2019.splashcon.org/details/splash-2019-Onward-papers/7/Storage-Combinators"&gt;storage combinator&lt;/a&gt; for interacting with data in S3.
&lt;/li&gt;
&lt;li&gt;A text field inside a window, defined as object literals.
&lt;/li&gt;
&lt;li&gt;A connection between the text field and a specific S3 bucket.
&lt;/li&gt;
&lt;/ol&gt;

That's it, and it is no coincidence that the structure of the system maps directly onto the structure
of the code.  Let's look at the parts in detail.

&lt;h3&gt;S3 via Storage Combinator&lt;/h3&gt;

The first line of the script sets up an S3 scheme handler so we can interact with the S3 buckets
almost as if they were local variables.  For example the following assignment statement stores
the text 'Hello World!' in the "msg.txt" file of "bucket1":&lt;p&gt;

&lt;code&gt;&lt;pre&gt;   s3:bucket1/msg.txt ← 'Hello World!'&lt;/pre&gt;&lt;/code&gt;

Retrieving it works similarly:&lt;p&gt;

&lt;code&gt;&lt;pre&gt;   stdout println: s3:bucket1/msg.txt&lt;/pre&gt;&lt;/code&gt;

The URL of our S3 simulator is &lt;code&gt;http://defiant.local:2345/&lt;/code&gt;, so running on host &lt;code&gt;defiant&lt;/code&gt; in the local network, addressed by Bonjour and listening on port 2345.  As Objective-S supports &lt;a href="https://dl.acm.org/doi/10.1145/2508168.2508169?cid=81316491227"&gt;Polymorphic Identifiers&lt;/a&gt; (&lt;a href="https://www.hirschfeld.org/writings/media/WeiherHirschfeld_2013_PolymorphicIdentifiersUniformResourceAccessInObjectiveSmalltalk_AcmDL.pdf"&gt;pdf&lt;/a&gt;),
this URL is a directly evaluable identifier in the language.

Alas, that directness poses a problem, because writing down an identifier in most programming 
languages yields the
value of the variable the identifier identifies, and Objective-S is no exception.  In the case of
&lt;code&gt;http://defiant.local:2345/&lt;/code&gt;, that value is the directory listing of the root of the S3 server, encoded as the following XML response:&lt;p&gt;

&lt;code&gt;
&lt;pre&gt;
&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"&amp;gt;
&amp;lt;Owner&amp;gt;&amp;lt;ID&amp;gt;123&amp;lt;/ID&amp;gt;&amp;lt;DisplayName&amp;gt;FakeS3&amp;lt;/DisplayName&amp;gt;&amp;lt;/Owner&amp;gt;
&amp;lt;Buckets&amp;gt;
&amp;lt;Bucket&amp;gt;
&amp;lt;Name&amp;gt;bucket1&amp;lt;/Name&amp;gt;
&amp;lt;CreationDate&amp;gt;2022-08-10T15:18:32.000Z&amp;lt;/CreationDate&amp;gt;
&amp;lt;/Bucket&amp;gt;
&amp;lt;/Buckets&amp;gt;
&amp;lt;/ListAllMyBucketsResult&amp;gt;
&lt;/pre&gt;
&lt;/code&gt;

That's not really what we want, we want to refer to the URL itself.  The &lt;code&gt;ref:&lt;/code&gt; allows
us to do this by preventing evaluation and thus returning the reference itself, very similar to
the &lt;code&gt;&amp;amp;&lt;/code&gt; operator that creates pointers in C.&lt;p&gt;

Except that an Objective-S reference (or more precisely, a &lt;em&gt;binding&lt;/em&gt;) is much richer than
a C pointer.  One of its many capabilities is that it can be turned into a store by sending it 
the &lt;code&gt;-asScheme&lt;/code&gt; message.  This new store uses the reference it was created from as its
base URL, all the references it receives are evaluated relative to this base reference.&lt;p&gt;

The upshot is that with the &lt;code&gt;s3:&lt;/code&gt; scheme handler defined and installed as described, the
expression &lt;code&gt;s3:bucket1/msg.txt&lt;/code&gt; evaluates to
&lt;code&gt;http://defiant.local:2345/bucket1/msg.txt&lt;/code&gt;.&lt;p&gt;

This way of defining shorthands has proven extremely useful for making complex references usable
and modular, and is an extremely common pattern in Objective-S code.&lt;p&gt;


&lt;h3&gt;Declarative GUI with object literals&lt;/h3&gt;

Next, we need to define the GUI: a window with a text field.  With object literals, this
is pretty trivial.  Object literals are similar to dictionary literals, except that you
get to define the class of the instance defined by the key/value pairs, instead of it
always being a dictionary.&lt;p&gt;

For example, the following literal defines a text field with certain dimensions and assigns it
to the &lt;code&gt;text&lt;/code&gt; local variable:

&lt;code&gt;&lt;pre&gt;   text ← #NSTextField{ #stringValue:'',#frame:(10@45 extent:180@24) }.&lt;/pre&gt;&lt;/code&gt;

And a window that contains the text field we just defined:

&lt;code&gt;&lt;pre&gt;   window ← #NSWindow{ #frame:(300@300 extent:200@105),#title:'S3', #views:#[text]}.&lt;/pre&gt;&lt;/code&gt;

It would have been nice to define the text field inline in its window definition, but we currently
still need a variable so we can connect the text field (see next section).

&lt;h3&gt;Connecting components&lt;/h3&gt;

Now that we have a text field (in a window) and somewhere to store the data, we need to connect
these two components.  Typically, this would involve defining some procedure(s), callback(s) or 
some extra-linguistics mechanism to mediate or define that connection.  In Objective-S, 
we just connect the components:&lt;p&gt;

&lt;code&gt;&lt;pre&gt;   text → ref:s3:bucket1/msg.txt.&lt;/pre&gt;&lt;/code&gt;

That's it.&lt;p&gt;

The right-arrow "→" is a polymorphic connection "operator".  The complete connection is
actually significantly more complex:

&lt;ol&gt;
&lt;li&gt;From a port of the source component&lt;/li&gt;
&lt;li&gt;To a role of the mediating connector compatible with that source port&lt;/li&gt;
&lt;li&gt;To a role of the mediating connector compatible with the target object's port&lt;/li&gt;
&lt;li&gt;To that compatible port of the target component&lt;/li&gt;
&lt;/ol&gt;

If you want, you can actually specify all these intermediate steps, but most of the time
you don't have to, as the machinery can figure out what ports and roles are compatible.
In this case, even the actual connector was determined automatically.&lt;p&gt;

If we didn't want a remote S3 bucket, we could also have stored the data in a local file,
for example:&lt;p&gt;

&lt;code&gt;&lt;pre&gt;   text → ref:file:/tmp/msg.txt.&lt;/pre&gt;&lt;/code&gt;

That treats the file like a variable, replacing the entire contents of the file with 
the text that was entered.  Speaking of variables, we could of course also store the
text in a local variable:&lt;p&gt;

&lt;code&gt;&lt;pre&gt;   text → ref:var:message.&lt;/pre&gt;&lt;/code&gt;

In our simple example that doesn't make a lot of sense because the variable
isn't visible anywhere and will disappear once the script terminates, but
in a larger application it could then trigger further processing.&lt;p&gt;

Alternatively, we could also append the individual messages to a stream, for
example to &lt;code&gt;stdout&lt;/code&gt;:

&lt;code&gt;&lt;pre&gt;   text → stdout.&lt;/pre&gt;&lt;/code&gt;

So every time the user hits return in the text field, the content of the text
field is written to the console.  Or appended to a file, by connecting to the 
stream associated with the file rather the file reference itself:

&lt;code&gt;&lt;pre&gt;   text → ref:file:/tmp/msg.txt outputStream.&lt;/pre&gt;&lt;/code&gt;

This doesn't have to be a single stream sink, it can be a complex
processing pipeline.&lt;p&gt;

I hope this makes it clear, or at least strongly hints, that this
is not the usual low-code/no-code trick of achieving compact code
by creating super-specialised components and mechanisms that work
well for a specific application, but immediately break down when
pushed beyond the demo.&lt;p&gt;

What it is instead is a new way of creating components, defining
their interfaces and then &lt;a href="https://blog.metaobject.com/2019/02/why-architecture-oriented-programming.html"&gt;gluing&lt;/a&gt; them together in a very straightforward
fashion.&lt;p&gt;


&lt;h3&gt;Eval/apply vs. connect and run&lt;/h3&gt;

Having constructed our system by configuring and connecting components, what's
left is running it.  &lt;code&gt;CLIApp&lt;/code&gt; is a subclass of &lt;code&gt;NSApplication&lt;/code&gt;
that knows how to run without an associated app wrapper or &lt;code&gt;Info.plist&lt;/code&gt;
file.  It is actually instantiated by the &lt;code&gt;stui&lt;/code&gt; script runner before
the script is started, with the instance dropped into the &lt;code&gt;app&lt;/code&gt; variable
for the script.&lt;p&gt;

This is where we leave our brave new world of connected components and
return (or connect with) the call/return world, similar to the way Cocoa's auto-generated
&lt;code&gt;main&lt;/code&gt; with call to &lt;code&gt;NSApplicationMain()&lt;/code&gt; works.&lt;p&gt;

The difference between eval/apply (call/return) and connect/run is actually quite profound, but
more on that in another post.&lt;p&gt;

Of course, we didn't leave call/return behind, it is still present and useful for certain
tasks, such as transforming an element into something slightly different.  However, for
constructing systems, having components that can be defined, configured and connected 
directly ("declaratively") is far superior to doing so procedurally, even than the
fluent APIs that have recently popped up and that have been mislabeled as "declarative".&lt;p&gt;

This project is turning out even better than I expected.  I am stoked.&lt;p&gt;</description><author>metablog</author><pubDate>Thu, 11 Aug 2022 04:55:16 GMT</pubDate><guid isPermaLink="true">https://blog.metaobject.com/2022/08/native-gui-distributed-system-in-tweet.html</guid></item><item><title>CLI tip 14: specify permissions during directory creation</title><link>https://learnbyexample.github.io/tips/cli-tip-14/</link><description>&lt;p&gt;You can use &lt;code&gt;mkdir -m&lt;/code&gt; instead of creating a directory with &lt;code&gt;mkdir&lt;/code&gt; first and then changing the directory permissions with the &lt;code&gt;chmod&lt;/code&gt; command. The argument to the &lt;code&gt;-m&lt;/code&gt; (mode) option uses the same syntax as the &lt;code&gt;chmod&lt;/code&gt; command.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# instead of this
&lt;/span&gt;&lt;span&gt;$ mkdir back_up
&lt;/span&gt;&lt;span&gt;$ chmod &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;750&lt;/span&gt;&lt;span&gt; back_up
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# do this
&lt;/span&gt;&lt;span&gt;$ mkdir &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;750&lt;/span&gt;&lt;span&gt; back_up
&lt;/span&gt;&lt;span&gt;$ stat &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%a %A&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt; back_up
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;750&lt;/span&gt;&lt;span&gt; drwxr&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;---
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are some more examples:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ mkdir &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span&gt;rx dummy_dir
&lt;/span&gt;&lt;span&gt;$ stat &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%a %A&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt; dummy_dir
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;555&lt;/span&gt;&lt;span&gt; dr&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;xr&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;xr&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;x
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ mkdir &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m go&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;rwx dot_files
&lt;/span&gt;&lt;span&gt;$ stat &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%a %A&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt; dot_files
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;700&lt;/span&gt;&lt;span&gt; drwx&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;------
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/cli-computing"&gt;Linux Command Line Computing&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 09 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-14/</guid></item><item><title>Tools I use: Eclipse</title><link>https://blog.bayindirh.io/blog/tools-i-use-eclipse/</link><description>&lt;p&gt;This is first of a series of posts where I talk about the tools and technologies I prefer to use. They are not intended to be in-depth technical documents, but posts answering the questions like Why &amp;amp; How with the history behind it. As always, all comments are welcome.&lt;/p&gt;
&lt;p&gt;Eclipse is an IDE framework. A complex scaffolding which can host a lot of functionality at the same time. This means an Eclipse installation can be almost anything, and many things at once. You want a C++ IDE? Check. Python? Check. Java? Go? Web development? Check, check &amp;amp; check.&lt;/p&gt;
&lt;p&gt;This makes Eclipse decidedly different from other tools at the same category, and puts it somewhere between an old school IDE and a modern code-aware text editor with plugins. As a result, when a newcomer sees Eclipse first time, there's a big, unfamiliar terrain to navigate.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Eclipse in Python perspective" src="https://mataroa.blog/images/9925a14b.jpeg" /&gt;&lt;/p&gt;
&lt;p&gt;Moreover, Eclipse is old. Around 20 years old, to be precise. As a result, it doesn't follow the new conventions, styling, UI densities, and whatnot from current era. It's written in Java. In other words, It's a prehistoric artifact when evaluated from a technology perspective.&lt;/p&gt;
&lt;p&gt;Or is it?&lt;/p&gt;
&lt;p&gt;Personally, I'm using Eclipse since 2006. Before that, I have used various software on and off, but while I was developing my graduation project, I needed a Java IDE, and found Eclipse. It was acceptably fast, worked on both Windows and Linux (I was dual-booting at that time), and most importantly, it was portable. I installed Eclipse to a 256MB flash drive alongside my workspace, and used that USB flash drive to work on my code while I was at the university (laptops were luxury back then).&lt;/p&gt;
&lt;p&gt;Eclipse provided great Java tools at that time (it was on par with greatest IDEs of the time for Java), and allowed me to develop and debug my graduation and master's projects. I've published papers from these research projects, too. Being able to develop, debug and oversee the whole process from a single point hooked me to Eclipse.&lt;/p&gt;
&lt;p&gt;Then, I found out that Eclipse can do more than Java (and Subversion).&lt;/p&gt;
&lt;p&gt;Being interested in C++ lead me to install C/C++ Development Tools (CDT), and Linux profiling integration tools (Linux Tools). Then, Eclipse published its Git integration. Installing these three things converted Eclipse to a modern, Linux native C/C++ development environment with a single click. Eclipse has a notion called "Perspectives", which are "task oriented views" in its essence. With perspectives, Eclipse can transform on the fly, and doesn't get cluttered.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Eclipse in Git perspective" src="https://mataroa.blog/images/341f1d5c.jpeg" /&gt;&lt;/p&gt;
&lt;p&gt;While Eclipse had its dark periods of being a heavy, slow and crash-prone application, especially in the C++ department, the project found its footing in the last 7-8 years, and fixed all its problems, and changed to a quarterly release schedule. While history of Eclipse warrants a single and much longer post, let's get into how I use Eclipse.&lt;/p&gt;
&lt;p&gt;Eclipse puts "Integrated" into IDE firmly and squarely.&lt;/p&gt;
&lt;p&gt;Eclipse uses "Projects" to store everything related to a project, including its source, settings, and everything in between. A project can override any global setting, and these settings are carried with the project itself. While not favored broadly, by submitting these files into your Git repository, you can carry all your pipeline with the source itself. This allows me to carry and share a project with all its intricate details and settings without detailed documentation and scripts. All are there when I import my project back to Eclipse.&lt;/p&gt;
&lt;p&gt;On top of that, Eclipse supports a great deal of programmability out of the box. This means, almost every path and every setting can contain variables. Using these variables allows a project to behave the same way between systems, operating systems and directory trees, making it more portable.&lt;/p&gt;
&lt;p&gt;Another feature I love is "Profiles". A project can have many build and debug profiles, which can contain different compiler flags, toolchains, folder includes and excludes, and environment variables. As a result, you can target different architectures, feature/optimization levels, or in extreme cases, a different source tree. This last feature makes compiling test suites with &lt;a href="https://github.com/catchorg/Catch2/tree/v2.x"&gt;Catch 2&lt;/a&gt; a breeze. While I didn't use extensively, you can even tune which ELF parser to use for debugging and understanding your errors, per profile.&lt;/p&gt;
&lt;p&gt;Eclipse has an integrated Git client for a long time. Arguably, it's the best Git client I have ever used (&lt;a href="https://www.git-tower.com/mac"&gt;Git Tower&lt;/a&gt; comes a close second). It's completely integrated to all views, provides great visual aid for history, encapsulates all common operations to easy to understand flows, and has a useful, integrated diffing tool. Moreover, it guides you during conflict resolution, provides advanced push/pull/merge/rebase controls and even discourages you from doing wrong things with your repo.&lt;/p&gt;
&lt;p&gt;On the language specific features provided by the "Toolkits", C/C++ Development Tools' indexer is something worth mentioning. It's called an indexer, but for historic reasons. It supports auto-completion (incl. templates), code formatting (with different profiles nonetheless), documentation access, declaration/instantiation location, advanced refactoring, code analysis, and probably some other things I didn't need or explore yet.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Eclipse's CDT settings window" src="https://mataroa.blog/images/aa4a82c5.jpeg" /&gt;&lt;/p&gt;
&lt;p&gt;When combined with Linux Tools (e.g. Valgrind), you can run the tests and profiling from your Eclipse window and get your results directly into your window, with graphs and annotations on your source code directly. This is a true integration. Not "tool launch" support.&lt;/p&gt;
&lt;p&gt;PyDev, which is the Python development environment for Eclipse, provides almost the same set of features, and some Python specific ones, as well.&lt;/p&gt;
&lt;p&gt;The last part I want to touch in this category is synchronization, and export/import capabilities.&lt;/p&gt;
&lt;p&gt;You can export all your configuration (installed items) and settings in Eclipse, with small XML files. This allows you or anyone to backup or share your Eclipse installation. You can import your configuration to any Eclipse installation to transform it to the Eclipse you got used to, and import your preferences on top of it to continue from where you left. If you want a more automatic way, you can login to your Eclipse account from any number of installations and keep them in sync via Oomph feature.&lt;/p&gt;
&lt;p&gt;There are more Eclipse features I'm aware of, but don't use actively. Hence, I'll leave a concise list of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Language Server Protocol support.&lt;/li&gt;
&lt;li&gt;Compile into / Run in Docker container.&lt;/li&gt;
&lt;li&gt;Remote development support (via SSH or dedicated daemon).&lt;/li&gt;
&lt;li&gt;Automatic Change Log generation.&lt;/li&gt;
&lt;li&gt;True multi monitor / multi window support.&lt;/li&gt;
&lt;li&gt;A broad official package ecosystem.&lt;/li&gt;
&lt;li&gt;A board third party package ecosystem via official Marketplace.&lt;/li&gt;
&lt;li&gt;...and many more.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a result, today's Eclipse is neither slow, nor heavy (it uses less RAM than a certain, popular editor of today), nor left behind. With its quarterly updates, diverse package and tool integration ecosystem, it's as capable and flexible as any tool used by today's developers.&lt;/p&gt;
&lt;p&gt;On top of that, Eclipse provides a true, single point of command and control for all the software development pipeline, from foundation to testing to deployment/publishing. It's a true marvel and powerhouse.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Tue, 09 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/tools-i-use-eclipse/</guid></item><item><title>Python tip 14: sequence unpacking</title><link>https://learnbyexample.github.io/tips/python-tip-14/</link><description>&lt;p&gt;You can assign the individual elements of a sequence to multiple variables. This is known as &lt;strong&gt;sequence unpacking&lt;/strong&gt; and it is handy in many situations.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;details &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'2018-10-25'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2346&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;purchase_date, vehicle, qty &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;details
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;purchase_date
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'2018-10-25'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;vehicle
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'car'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;qty
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2346
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's how you can easily assign and swap multiple variables.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #7f8989;"&gt;# multiple assignments
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;num1, num2, num3 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3.14&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# swapping values
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;num1, num2, num3 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;num3, num1, num2
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{num1 = }&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\n&lt;/span&gt;&lt;span&gt;{num2 = }&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\n&lt;/span&gt;&lt;span&gt;{num3 = }&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;num1 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= -&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100
&lt;/span&gt;&lt;span&gt;num2 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3.14
&lt;/span&gt;&lt;span&gt;num3 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unpacking isn't limited to mapping every element of the sequence. You can use a &lt;code&gt;*&lt;/code&gt; prefix to catch all the remaining values (if any is left) in a &lt;code&gt;list&lt;/code&gt; variable.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;values &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'first'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;200&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;300&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'last'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;x, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;y &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;values
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;x
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'first'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;y
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;200&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;300&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'last'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;s1, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;nums, s2 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;values
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;s1
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'first'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;200&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;300&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;s2
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'last'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://mathspp.com/blog/pydonts/unpacking-with-starred-assignments"&gt;Unpacking with starred assignments&lt;/a&gt; for more examples and explanations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Mon, 08 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-14/</guid></item><item><title>Breaking Barbarian</title><link>https://www.swyx.io/breaking-barbarian</link><description>&lt;p&gt;This week in a &lt;a href="https://twitter.com/swyx/status/1555596996744028160"&gt;Svelte Radio recording&lt;/a&gt;, @rich-harris commented that something I said was "uniquely swyx": an offhand observation that "we are all professional streamers now" [^1]. I responded that I've been calling this behavior "barbarianism" - you can listen to the full explanation &lt;a href="https://www.svelteradio.com/"&gt;when the episode drops in future&lt;/a&gt;.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Mon, 08 Aug 2022 01:51:07 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/breaking-barbarian</guid></item><item><title>2022–08–06: Pinephone keyboard bugs and new findings</title><link>https://xnux.eu/log/#072</link><author>megi's PinePhone Development Log</author><pubDate>Sat, 06 Aug 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#072</guid></item><item><title>Botspam Apocalypse</title><link>https://www.marginalia.nu/log/61-botspam-apocalypse/</link><description>&lt;p&gt;Bots are absolutely crippling the Internet ecosystem.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;future&amp;rdquo; in the film Terminator 2 is set in the 2020s. If you apply its predictions to the running of a website, it&amp;rsquo;s honestly very accurate.&lt;/p&gt;
&lt;p&gt;Modern bot traffic is virtually indistinguishable from human traffic, and can pummel any self-hosted service into the ground, flood any form with comment spam, and is a chronic headache for almost any small scale web service operator.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Wed, 03 Aug 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/61-botspam-apocalypse/</guid></item><item><title>How good a Data Scientist is GPT-3?</title><link>https://bytepawn.com/how-good-a-data-scientist-is-gpt-3.html</link><description>&lt;p&gt;Recently I have been playing around with OpenAI's GPT-3 and I am very impressed by it. It reminds of the famous Arthur C. Clarke quote, &lt;em&gt;“Any sufficiently advanced technology is indistinguishable from magic.”&lt;/em&gt; Here I will show a "conversation" with GPT-3 to gauge how good a Data Scientist — or an illusion of a Data Scientist — it is.&lt;br /&gt;&lt;br /&gt; &lt;img alt="GPT-3" src="/images/gpt-3.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 31 Jul 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/how-good-a-data-scientist-is-gpt-3.html</guid></item><item><title>The Great Unzippening</title><link>https://www.swyx.io/the-great-unzippening</link><description>&lt;p&gt;Society is splintering in an unacceptable way and I have a metaphor for it.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sat, 30 Jul 2022 06:26:29 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/the-great-unzippening</guid></item><item><title>Waste Spammers Time to Kill Their Return on Investment</title><link>https://www.brightball.com/articles/waste-spammers-time-to-reduce-their-return-on-investment</link><description>Continuing our series from 2012 where I accidentally ended up combating phishing and fraud for a year, we move onto the spam issue. Everything that happened that year was an exercise in triage. Problems were everywhere on the system and in the marketplace. The site I was working on was the leader in a niche space but it wasn't just the phish who tried to capitalize on the chaos, it was our competitors too.
Spam takes a time investment and every time investment is a business decision. If you can't stop it completely, you can at least dramatically increase their costs...and have fun doing it.</description><author>Brightball Articles</author><pubDate>Sat, 30 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.brightball.com/articles/waste-spammers-time-to-reduce-their-return-on-investment</guid></item><item><title>On composability</title><link>https://blog.bayindirh.io/blog/on-composability/</link><description>&lt;p&gt;Lately, I’m working on a new tool which will help me to automate the tasks I manually do using my desktop computer. While these tasks are mundane, they increase life quality of me and many individuals. As I mentioned before, I won’t have a Linux desktop system, and will move to a Mac laptop.&lt;/p&gt;
&lt;p&gt;Naturally, I wanted to move these workflows to macOS.&lt;/p&gt;
&lt;p&gt;Moving these workflows to macOS is indeed possible. However, I wanted to automate them to save time and create consistent outputs while at it, and this proved to be a different story.&lt;/p&gt;
&lt;p&gt;macOS has automation capabilities, namely &lt;a href="https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/introduction/ASLR_intro.html"&gt;AppleScript&lt;/a&gt; and &lt;a href="https://support.apple.com/guide/automator/welcome/mac"&gt;Automator&lt;/a&gt;. First one is in &lt;a href="https://developer.apple.com/forums/thread/112551"&gt;maintenance mode&lt;/a&gt; for a long time, and second one relies on endpoints published by applications themselves. Moreover, Apple doesn’t want you to enable these third party automations much, and the software I have doesn’t expose the functionality I need.&lt;/p&gt;
&lt;p&gt;However, Automator has one more trick: ability to run &lt;code&gt;.sh&lt;/code&gt; scripts.  That would be useful, if the software I had CLI counterparts (like Tower, BBEdit and Monodraw), but no, they are GUI first apps.&lt;/p&gt;
&lt;p&gt;Hence, I can’t automate the tasks the way I need on macOS. Also, I’m not a fan of Homebrew and other package managers for macOS, hence I’m stuck. &lt;/p&gt;
&lt;p&gt;Then, I remembered having no desktop computer doesn't mean I can't run Linux.&lt;/p&gt;
&lt;p&gt;I took out a Raspberry Pi 3, installed a 64 bit OS, and started to play around, then decided to design the tool I mentioned at the beginning of this post. While designing the system I wanted to create, something made itself apparent.&lt;/p&gt;
&lt;p&gt;The magic of Linux is rooted in its composability.&lt;/p&gt;
&lt;p&gt;To create the system I want, I can use a lot of available packages, plug them together, and lastly write the little tool which binds them (yes, like The Ring), and create the bigger system I have dreamt of. &lt;/p&gt;
&lt;p&gt;Today's developers use and exploit these &lt;a href="https://en.wikipedia.org/wiki/Unix_philosophy#Doug_McIlroy_on_Unix_programming"&gt;principles&lt;/a&gt; a lot, and build amazing things with them. Since they didn't live in a world where these things are absent, they take these features as granted and sometimes do not apply the same principles, or underestimate the power of them.&lt;/p&gt;
&lt;p&gt;It's important to understand that the UNIX principles and the GPL protecting the tools which makes this composability possible underpins and enables almost everything we do with Linux systems today. Dismissing them as useless, old-fashioned or backwards is equal to cutting the branch we're sitting on.&lt;/p&gt;
&lt;p&gt;Until next time,&lt;/p&gt;
&lt;p&gt;Be kind.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Sat, 30 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/on-composability/</guid></item><item><title>Please stop citing TIOBE</title><link>https://nindalf.com/posts/stop-citing-tiobe/</link><description>This article critiques the TIOBE Programming Community index and provides better ways to evaluate programming languages for projects and as a developer.</description><author>Krishna's blog</author><pubDate>Thu, 28 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/stop-citing-tiobe/</guid></item><item><title>Use One Big Server</title><link>https://specbranch.com/posts/one-big-server/</link><description>&lt;p&gt;A lot of ink is spent on the &amp;quot;monoliths vs. microservices&amp;quot; debate, but the real issue behind
this debate is about whether distributed system architecture is worth the developer time and
cost overheads.  By thinking about the real operational considerations of our systems, we can
get some insight into whether we actually need distributed systems for most things.&lt;/p&gt;
&lt;p&gt;We have all gotten so familiar with virtualization and abstractions between our software
and the servers that run it.  These days, &amp;quot;serverless&amp;quot; computing is all the rage, and even
&amp;quot;bare metal&amp;quot; is a class of virtual machine.  However, every piece of software runs on a
server.  Since we now live in a world of virtualization, most of these servers are a lot
bigger and a lot cheaper than we actually think.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Wed, 27 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/one-big-server/</guid></item><item><title>The Poor American Narrative</title><link>https://jodavaho.io/posts/poor-american-narrative.html</link><description>&lt;p&gt;I recently read a wonderful piece by the New York Times titled &amp;ldquo;&lt;a href="https://www.nytimes.com/interactive/2022/07/28/opinion/focus-group-political-division.html"&gt;What happened when 7 Trump voters and 6 Biden voters tried to find common ground&lt;/a&gt;&amp;rdquo;.
What struck me was how quickly even the most middling of issues quickly diverged along party lines, often with classic party narratives appearing.
It is absolutely worth a read.&lt;/p&gt;
&lt;p&gt;These folks are living profoundly different American experiences, and yet both feel that the future is bleak.
Today, one person can blithely say that an entire political party, or an entire race, or an entire economic group, or even the entire country is to blame for what they believe is the fundamental problem in the country.
&amp;ldquo;Systemic racism&amp;rdquo;, &amp;ldquo;Illegal immegrants&amp;rdquo;, &amp;ldquo;White people&amp;rdquo;, &amp;ldquo;Corporations&amp;rdquo;, &amp;ldquo;Billionaires&amp;rdquo;, &amp;ldquo;Religion&amp;rdquo;.
At least one participant all but admitted this, saying the country needs to be torn down and rebuilt.&lt;/p&gt;
&lt;p&gt;The entire nation, it seems, has embraced a kind of catastrophic negative self-talk.&lt;/p&gt;
&lt;p&gt;Why?&lt;br /&gt;
At the risk of sounding trite, I think the stories we tell ourselves matter.
We force ourselves, or are forced by others, to focus on the negative things happening to &lt;em&gt;our group&lt;/em&gt;, especially as perptrated by &lt;em&gt;another group&lt;/em&gt;.
Our internal narrative tells us the bad people are everywhere, they have no concern for our wellbeing or in fact want to hurt us, they are taking power from us for their own selfish desires.
They are unfeeling, uncaring, malicious, and irredeemably so.
They are not part of the solution, they are a maniacal distraction from progress towards a better world.&lt;/p&gt;
&lt;p&gt;If a person were generating these narratives internally, they would have legitimate reason to seek professional help with their mental health.&lt;/p&gt;
&lt;p&gt;The three main narratives of depression can be summarized as:
&amp;ldquo;I&amp;rsquo;m bad. The world is bad. There&amp;rsquo;s nothing anyone can do about it&amp;rdquo;
&lt;a href=""&gt;1&lt;/a&gt;
Whatever the troubles of the world, a laser focus on the negative and how it reinforces a fundamentally dire internal narrative is a big part of the definition of clinical depression.
Believing that problems are so big that there is nothing one can undertake to change the narrative is another.
Words like &amp;ldquo;systemic&amp;rdquo; are excellent for this! How does one non-violently dismantle a whole system!
All that&amp;rsquo;s missing is the sense that &lt;em&gt;oneself&lt;/em&gt; is somehow fundamentally flawed, and if you don&amp;rsquo;t think that already, someone outside your political persuasion is happy to tell you this.&lt;/p&gt;
&lt;p&gt;And yet, because we allow others to generate this narrative, and reinforce it in us, we don&amp;rsquo;t wonder at it.
We don&amp;rsquo;t seek help getting rid of it. It&amp;rsquo;s not unhealthy! I&amp;rsquo;m awake when everyone else is asleep!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m worried we&amp;rsquo;re letting bad stories, even if they have a kernel of truth, dominate our attention.
I&amp;rsquo;m worried that we&amp;rsquo;re unaware that obsessive negative self-talk is fundamentally changing the way we see eachother, our institutions, and our country, in a way that blinds us to what is positive and what is possible.
I&amp;rsquo;m worried this causes us to &amp;ldquo;write off&amp;rdquo; whole groups of people simply because the story says they are fundamentally bad.
I&amp;rsquo;m concerned that we have personally allowed these stories to become all-consuming, so that even unrelated negative events, even &lt;em&gt;minor&lt;/em&gt; unrelated events, are getting vacuumed up in a false causal relationship.&lt;/p&gt;
&lt;p&gt;Research into depression and mental illness has identified this pattern repeatedly, and has a worthwhile answer.&lt;/p&gt;
&lt;p&gt;The answer is trite, but I believe important.
It is something each person can do.
We must positively reframe every event, every news story, and every political cycle by default.
We have to learn to see the good in day-to-day events.
We need to learn to look plainly at societal problems believing that a resolution is possible and those who disagree with you are part of the solution, not the cause of the problem.
And we need to mention this positive reframing to others, to set an example about a more healthy way of thinking and problem solving.&lt;/p&gt;
&lt;p&gt;There are not concise, key causes to all the worlds evils. Down that road is madness.&lt;/p&gt;
&lt;h1 id="license"&gt;License&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://creativecommons.org/licenses/by-sa/4.0/deed.ast"&gt;CC BY-SA 4.0&lt;/a&gt;&lt;/p&gt;</description><author>jodavaho.io</author><pubDate>Tue, 26 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jodavaho.io/posts/poor-american-narrative.html</guid></item><item><title>Vim tip 12: save and restore sessions</title><link>https://learnbyexample.github.io/tips/vim-tip-12/</link><description>&lt;p&gt;You can save and restore Vim sessions to continue working with the same setup before you had to quit Vim for reasons like switching off the machine, switching to another project, etc.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;:mksession proj.vim&lt;/kbd&gt; save the current Vim session with details like cursor position, file list, layout, etc
&lt;ul&gt;
&lt;li&gt;you can customize things to be saved using the &lt;code&gt;sessionoptions&lt;/code&gt; setting&lt;/li&gt;
&lt;li&gt;for example, &lt;kbd&gt;:set sessionoptions+=resize&lt;/kbd&gt; will save resized window information as well&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:mksession! proj.vim&lt;/kbd&gt; overwrite existing session&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;:source proj.vim&lt;/kbd&gt; restore Vim session from &lt;code&gt;proj.vim&lt;/code&gt; file
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vim -S proj.vim&lt;/code&gt; restore a session from the command line when launching Vim&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/usr_21.txt.html#21.4"&gt;:h 21.4&lt;/a&gt;, &lt;a href="https://vimhelp.org/starting.txt.html#views-sessions"&gt;:h views-sessions&lt;/a&gt; and &lt;a href="https://vimhelp.org/options.txt.html#%27sessionoptions%27"&gt;:h 'sessionoptions'&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://stackoverflow.com/q/1642611/4082052"&gt;stackoverflow: How to save and restore multiple different sessions in Vim?&lt;/a&gt; for custom settings to automate the save and restore process and other tips and tricks. See also &lt;a href="https://github.com/iggredible/Learn-Vim/blob/master/ch20_views_sessions_viminfo.md"&gt;Learn-Vim: Views, Sessions, and Viminfo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 26 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-12/</guid></item><item><title>Enterprise Challenges with DMARC Deployment</title><link>https://www.brightball.com/articles/enterprise-challenges-with-dmarc-deployment</link><description>DMARC deployment projects in larger organizations come with their own variety of challenges. A great many more people are involved, so there will be more communication, more approvals and more politics. Others will object on the basis of size. "Our company is simply too large!" some will say.In the final section of our DMARC guide, we will discuss these common concerns and how to address the challenges. If 74% of the US Federal goverment did this in about a year, you can too.</description><author>Brightball Articles</author><pubDate>Mon, 25 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.brightball.com/articles/enterprise-challenges-with-dmarc-deployment</guid></item><item><title>Container scheduling strategies for integration testing 14 different databases in Github Actions</title><link>http://notes.eatonphil.com/2022-07-25-database-integration-testing.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-07-25-database-integration-testing.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Mon, 25 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/2022-07-25-database-integration-testing.html</guid></item><item><title>What to do when iCloud is stuck on uploading items</title><link>https://www.swyx.io/what-to-do-when-icloud-is-stuck-on-uploading-items</link><description>&lt;p&gt;I use iCloud as my syncing engine for my &lt;a href="https://www.swyx.io/obsidian-brain"&gt;Obsidian Second Brain&lt;/a&gt;, and twice now I've seen iCloud get corrupted into a really bad state. I also &lt;a href="https://github.com/sw-yx/brain"&gt;back up everything to github&lt;/a&gt;, so I dont really experience much data loss, but it is annoying to see iCloud be so unreliable at even the simple task of syncing mostly text files.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sun, 24 Jul 2022 21:52:42 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/what-to-do-when-icloud-is-stuck-on-uploading-items</guid></item><item><title>Deploying DMARC Without Breaking Everything</title><link>https://www.brightball.com/articles/deploying-dmarc-without-breaking-everything</link><description>Too scary? Messing with the configuration on your domain email is scary, especially if you're already sending a lot of it. You have to worry that you're going to screw something up and break all of the email communications for the entire company.
That's what I was worried when I first rolled this out and had no idea what I was doing. One of the reasons I'm such a big advocate for DMARC today is that it was painless, easy and involve no risk at all.</description><author>Brightball Articles</author><pubDate>Sat, 23 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.brightball.com/articles/deploying-dmarc-without-breaking-everything</guid></item><item><title>The Elements of Typographic Style</title><link>https://bytepawn.com/the-elements-of-typographic-style.html</link><description>&lt;p&gt;The Elements of Typographic Style by Robert Bringhurst is the most beautiful book I've ever held in my hand. This stunning piece of readable art shows Bringhurst's love for the craft of design, typography and writing, and his mastery of these subject, a result of his life-long devotion to them. I am not a professional typographer, but I enjoyed glancing at, reading and appreciating every page of this book.&lt;br /&gt;&lt;br /&gt; &lt;img alt="The Elments of Typographic Style" src="/images/teots_cover.jpg" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 23 Jul 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/the-elements-of-typographic-style.html</guid></item><item><title>The Culture Map</title><link>https://bytepawn.com/the-culture-map.html</link><description>&lt;p&gt;The Culture Map by Erin Meyer is a system of 8 scales which can be used to determine how cultures vary along a spectrum. The scales can be used to analyse one culture relative to another and decode how culture influences your international collaborations. I find the considerations in the book helpful irrespective of cultural background; the 8 scales can be applied to individuals as well, irrespective of where they are from.&lt;br /&gt;&lt;br /&gt; &lt;img alt="The Culture Map" src="/images/culture_map_cover.jpg" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 22 Jul 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/the-culture-map.html</guid></item><item><title>If you succeed, you will fail</title><link>https://boyter.org/posts/if-you-succeed-you-will-fail/</link><description>&lt;blockquote&gt;
&lt;p&gt;If you succeed, you will fail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Something said at a client engagement I was at some time ago. I figure enough time has passed that it is worth sharing this story.&lt;/p&gt;
&lt;p&gt;One of the early engagements was to deliver for a very large company an iOS Application powered by a RESTful API. This was problematic due to what is common for every large organisation, a collection of older legacy backends. Some with their own API&amp;rsquo;s, and bizzare authentication processes. Part of the deliverable was also working with push notifications for things like billing updates, documenting the systems (since few people knew how everything worked) and load testing.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Thu, 21 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/if-you-succeed-you-will-fail/</guid></item><item><title>CLI tip 13: join lines of two files based on the first field</title><link>https://learnbyexample.github.io/tips/cli-tip-13/</link><description>&lt;p&gt;By default, &lt;code&gt;join&lt;/code&gt; combines two files based on the first field content (also referred as &lt;strong&gt;key&lt;/strong&gt;). Only the lines with common keys will be part of the output. The key field will be displayed first in the output (this distinction will come into play if the first field isn't the key). Rest of the line will have the remaining fields from the first and second files, in that order. One or more blanks (space or tab) will be considered as the input field separator and a single space will be used as the output field separator. If present, blank characters at the start of the input lines will be ignored.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# sample sorted input files
&lt;/span&gt;&lt;span&gt;$ cat jan.txt
&lt;/span&gt;&lt;span&gt;apple   &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;banana  &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;20
&lt;/span&gt;&lt;span&gt;soap    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3
&lt;/span&gt;&lt;span&gt;tshirt  &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3
&lt;/span&gt;&lt;span&gt;$ cat feb.txt
&lt;/span&gt;&lt;span&gt;banana  &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;15
&lt;/span&gt;&lt;span&gt;fig     &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100
&lt;/span&gt;&lt;span&gt;pen     &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2
&lt;/span&gt;&lt;span&gt;soap    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# combine common lines based on the first field
&lt;/span&gt;&lt;span&gt;$ join jan.txt feb.txt
&lt;/span&gt;&lt;span&gt;banana &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;20 15
&lt;/span&gt;&lt;span&gt;soap &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's an &lt;code&gt;awk&lt;/code&gt; version to do the same. Helpful if you want to do some additional processing that won't be possible with the &lt;code&gt;join&lt;/code&gt; command. Another advantage is that this solution will work even if the input files are not sorted.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'NR==FNR{a[$1]=$2; next} $1 in a{print $1, a[$1], $2}'&lt;/span&gt;&lt;span&gt; jan.txt feb.txt
&lt;/span&gt;&lt;span&gt;banana &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;20 15
&lt;/span&gt;&lt;span&gt;soap &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://learnbyexample.github.io/cli_text_processing_coreutils/join.html"&gt;join chapter&lt;/a&gt; from my &lt;a href="https://github.com/learnbyexample/cli_text_processing_coreutils"&gt;Command line text processing with GNU Coreutils&lt;/a&gt; ebook for more details and examples.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 20 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-13/</guid></item><item><title>The Trouble With Many Skeptics</title><link>https://blog.nawaz.org/posts/2022/Jul/the-trouble-with-many-skeptics/</link><description>&lt;p&gt;Back when I was at university, a friend mentioned to me that he wanted
to read &lt;em&gt;The Demon Haunted World&lt;/em&gt; by Carl Sagan. I had been a fan of
Sagan since my teenage years, but had put off reading that book. Asking
him if he&amp;#8217;d read any of Sagan …&lt;/p&gt;</description><author>Beetle Space</author><pubDate>Tue, 19 Jul 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.nawaz.org/posts/2022/Jul/the-trouble-with-many-skeptics/</guid></item><item><title>Word generation in Iron Arachne</title><link>https://benovermyer.com/blog/2022/07/word-generation-in-ironarachne/</link><description>&lt;p&gt;When I first rewrote Iron Arachne as a static JavaScript website, I quickly hacked together several name generators using different methods. Most assembled pieces from several different chunks into a single word.&lt;/p&gt;
&lt;p&gt;That quickly became insufficient. The results were predictable and small in number. After awhile, I wrote a simple module called "invented" which was meant to create words for invented languages, or conlangs. It wasn't a full language generator like previous iterations of Iron Arachne had. That still doesn't exist for the JavaScript version. However, it did have a simple pattern matching algorithm; if you passed it an array of strings, it would pick a random item from that array, and then go through that string character-by-character. Each character was a symbol representing a category of sounds - phonemes - that it would then pick from at random and return that. Most characters were lowercase letters. If a character was uppercase or not a letter, it would be returned unmodified - so a pattern like &lt;code&gt;KONG&lt;/code&gt; would always return "kong" and not something with random phonemes.&lt;/p&gt;
&lt;p&gt;The result was an invented word generator that worked well enough. I started using it in almost every part of Iron Arachne that needed made-up words.&lt;/p&gt;
&lt;p&gt;Recently, though, things changed just a little bit. I was running out of letters of the alphabet to use as symbols representing phoneme categories. I was using two of them - &lt;code&gt;u&lt;/code&gt; and &lt;code&gt;d&lt;/code&gt; - to represent a doubled vowel and consonant, respectively. I decided to reclaim those letters for other things. To do so, I needed to figure out how to change the system so I could still generate doubled letters but not linearly add new symbols for them.&lt;/p&gt;
&lt;p&gt;The solution was to add the first modifier symbol to the invented library. Instead of being a simple iterative lookup, the generate function would now store the last generated phoneme, and if the next symbol was a &lt;code&gt;+&lt;/code&gt; it would return that last phoneme instead of looking up a different one.&lt;/p&gt;
&lt;p&gt;That, in turn, made me think about a common scenario where I wanted to have a particular type of word use a random list of sounds instead of one of the pre-existing categories of phonemes. How would I do that, though? My existing module only checked each character in turn. Rather than try and continue down that route, I decided it was finally time to build an actual parser.&lt;/p&gt;
&lt;p&gt;I'd never written a parser before. Not even in CS, way back in high school and college. I pivoted to a history degree before taking the otherwise-inevitable compilers class. Lexers and parsers were something I used, not something I wrote. Even now, I'm cheating a bit and using regular expressions to handle most of the heavy lifting.&lt;/p&gt;
&lt;p&gt;The idea is that I'll be able to write patterns like this:&lt;/p&gt;
&lt;pre class="giallo" style="color: #F8F8F2; background-color: #282A36;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;(K,G)LvNGON&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the generator will spit out words like this:&lt;/p&gt;
&lt;pre class="giallo" style="color: #F8F8F2; background-color: #282A36;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;Klangon&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;Glingon&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;Glengon&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;Klungon&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So anytime the parser encounters a series of characters in parenthesis, it returns a random unmodified item from that list instead of a random phoneme from a lookup table. I want the system to be flexible enough that I can add additional workflows later. Perhaps I might want to add a way to return a random phoneme that rhymes with a pattern, for example.&lt;/p&gt;
&lt;p&gt;I haven't completed the new parser as I'm writing this. However, I imagine it'll be done sometime in the next few weeks.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Tue, 19 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/07/word-generation-in-ironarachne/</guid></item><item><title>Combating Phishing with DMARC</title><link>https://www.brightball.com/articles/combatting-phishing-with-dmarc-a-complete-guide</link><description>Email shouldn't feel like a dark art, but to a lot of people it does. Everyone should have DMARC setup by this point, but they don't. Here's the first piece of a 3 part guide covering why it works and how to set it up.Since writing about how to reverse account takeovers last week I've decided to write a security series covering all the weird things I encountered back in 2012, when I accidentally ended up combating phishing and fraud for a year. In the last article, the first recommendation was to setup DMARC. So let's take a deeper look at why, how and what's involved in long term management once it's setup.</description><author>Brightball Articles</author><pubDate>Mon, 18 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.brightball.com/articles/combatting-phishing-with-dmarc-a-complete-guide</guid></item><item><title>AWS Abusing Search Engine Gets Abused</title><link>https://boyter.org/posts/aws-abusing-search-engine-gets-abused/</link><description>&lt;p&gt;Some time ago I wrote about building an Australian search engine by abusing how AWS Lambdas work. You can view it at &lt;a href="https://bonzamate.com.au"&gt;bonzamate.com.au&lt;/a&gt;, and read the &lt;a href="https://boyter.org/posts/abusing-aws-to-make-a-search-engine/"&gt;post about it here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Recently I noticed that Bonzamate.com.au was in turn being abused by a series of bots repeatedly making queries against it.&lt;/p&gt;
&lt;p&gt;Now normally I don&amp;rsquo;t worry about bots. There is little you can do to stamp them out entirely, and its always nice to see someone trying to exploit the things you work on. However should the bots either result in degraded service or in this case increased personal costs to me I will actively try to work against them.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Sun, 17 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/aws-abusing-search-engine-gets-abused/</guid></item><item><title>How to Manifest a Meetup</title><link>https://www.swyx.io/manifest-meetups</link><description>&lt;blockquote&gt;
&lt;p&gt;2024 update: for those who work in devrel/organize less-social-more-technical meetups, I have now written &lt;a href="https://dx.tips/meetups-guide"&gt;How to Organize Meetups Good on Dx.tips&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sat, 16 Jul 2022 01:48:48 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/manifest-meetups</guid></item><item><title>Checklist For Evaluating Cloud Backup Services</title><link>https://blog.nawaz.org/posts/2022/Jul/checklist-for-evaluating-cloud-backup-services/</link><description>&lt;ol class="arabic simple"&gt;
&lt;li&gt;If I delete a file and sync, can I recover the deleted file?&lt;ul&gt;
&lt;li&gt;Is there a deadline (e.g. only within 90 days)? Or will they keep
it&amp;nbsp;forever?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If I made changes to the file and synced, can I access prior
versions?&lt;ul&gt;
&lt;li&gt;Is there a limit to how many …&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;</description><author>Beetle Space</author><pubDate>Thu, 14 Jul 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.nawaz.org/posts/2022/Jul/checklist-for-evaluating-cloud-backup-services/</guid></item><item><title>On Prescriptive Descriptions</title><link>https://www.marginalia.nu/log/60-prescriptive-descriptions/</link><description>&lt;p&gt;I&amp;rsquo;d like to discuss a mental somersault that I&amp;rsquo;ve found has caused me a lot of grief in the past, which is prescriptive descriptions. Let&amp;rsquo;s break this down a bit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A descriptive statement is a statement about how something is.&lt;/li&gt;
&lt;li&gt;A prescriptive statement is a statement about how something must be, a rule or a law.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If I stay up a bit late, do most of my work in the evenings, wake up tired and just sort of putter about until noon, I might describe myself as a night person because of this.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Thu, 14 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/60-prescriptive-descriptions/</guid></item><item><title>Python tip 13: formatting numbers with underscore separation</title><link>https://learnbyexample.github.io/tips/python-tip-13/</link><description>&lt;p&gt;For readability purposes, you can use underscores while declaring large numbers. For example:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1_000_000_000
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1000000000
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0b1000_1111
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;143
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Did you know that you can also format numbers with underscore separation?&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;14310023
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# underscore separation
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{n&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;:_&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'14_310_023'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# you can also use comma separation for integers
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{n&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;:,&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'14,310,023'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are some examples for displaying numbers in binary, octal and hexadecimal formats:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;14310023
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{n&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;:_b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'1101_1010_0101_1010_1000_0111'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{n&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;:#_b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'0b1101_1010_0101_1010_1000_0111'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{n&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;:#_x&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'0xda_5a87'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{n&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;:#_o&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'0o6645_5207'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's an example with zero filling:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; for &lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;20&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;28&lt;/span&gt;&lt;span&gt;):
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{n&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;:09_b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0000&lt;/span&gt;&lt;span&gt;_0011
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0001&lt;/span&gt;&lt;span&gt;_0100
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0001&lt;/span&gt;&lt;span&gt;_1100
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://docs.python.org/3/reference/lexical_analysis.html#f-strings"&gt;docs.python: Formatted string literals&lt;/a&gt; for documentation and other examples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 13 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-13/</guid></item><item><title>Automatically Reversing Account Takeovers</title><link>https://www.brightball.com/articles/automatically-reversing-account-takeovers</link><description>Today, Brian Krebs reported on account takeovers happening at Experian, one of the 3 major credit agencies. The first step after getting account access is to lock out the account owner, usually by swapping the email address. 10 years ago I dealt with this problem extensively, so I'd like to share how to solve it.</description><author>Brightball Articles</author><pubDate>Mon, 11 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.brightball.com/articles/automatically-reversing-account-takeovers</guid></item><item><title>Overstretching</title><link>https://blog.bayindirh.io/blog/overstretching/</link><description>&lt;p&gt;Recently, I have been following a lot of events that made me uneasy about the future of both GNU/Linux and Free Software in general. Normally I have been an observer in these events, but I found that I have formed pretty coherent set of ideas, feelings and preferences for the future evolution of these things.&lt;/p&gt;
&lt;p&gt;As a result, I've found myself inside many discussions about these topics, and I came out pretty unimpressed and disappointed about the current state of things. In a sense I have been disillusioned and found out that many fundamental aspects I support and defend is either misunderstood or dismissed as useless.&lt;/p&gt;
&lt;p&gt;Experiencing this, and trying to put my ideas forward has drained me beyond my comfort zone, and more importantly somewhat impaired my capacity to function in areas I need to function.&lt;/p&gt;
&lt;p&gt;This got me thinking. How can I continue to support the things I care without burning myself out and impairing my daily life?  The answer I found is to dive deeper into these subjects, learn more, and talk less, but in a richer manner. Because, I found out that I'm not knowledgeable enough to discuss the things at the depth I want to discuss, and counter the arguments I receive with the clarity I crave for.&lt;/p&gt;
&lt;p&gt;On the other hand, I'll commit more into the things I care. I'll be more strict about licensing my software, and where I host and serve said software. I may write more about these subjects in this blog, and voice my objections more frequently, but in a more kinder and easier to understand language.&lt;/p&gt;
&lt;p&gt;More importantly, I've found out that these turn of events have created the spark I have been missing for a long time. Settling into a comfortable software stack and unintentionally locking myself into a bubble has isolated me from the events which were taking place around me. I feel like I'm awaken from a long slumber. I think I can use this newfound energy and motivation for good things.&lt;/p&gt;
&lt;p&gt;Hope to see you around,&lt;/p&gt;
&lt;p&gt;Be kind.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Sun, 10 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/overstretching/</guid></item><item><title>Implementing a simple jq clone in Go, and basics of Go memory profiling</title><link>http://notes.eatonphil.com/implementing-a-jq-clone-in-go.html</link><description>&lt;p&gt;In this post we'll build a basic jq clone in Go. It will only be able
to pull a single path out of each object it reads. It won't be able to
do filters, mapping, etc.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./jqgo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;
&lt;span class="s2"&gt;&amp;quot;https://api.github.com/repos/petroav/6.828&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;&amp;quot;https://api.github.com/repos/rspt/rspt-theme&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We'll start by building a "control" implementation that uses Go's
builtin JSON library with a JSON path tool on top.&lt;/p&gt;
&lt;p&gt;Then we'll implement a basic path-aware JSON parser in 600 lines of
Go. It's going to use a technique (that may have a better name but) I
call "partial parsing" or "fuzzy parsing" where we fully parse what we
care about and only &lt;em&gt;sort of&lt;/em&gt; parse the rest.&lt;/p&gt;
&lt;p&gt;Why partial parsing? There are two general reasons. One is to use
less memory than parsers that must always turn all of a text into an
object in your language. The other is for when the language has
complexities you don't want or need to deal with. We'll basically have
to deal with all the complexities of JSON so this post is about the
former reason: using less memory. I've written about a case for the
second reason though in &lt;a href="https://datastation.multiprocess.io/blog/2021-10-31-building-a-nested-css-rule-expander.html"&gt;building a simple, fast SCSS
implementation&lt;/a&gt;.&lt;/p&gt;
&lt;p class="note"&gt;
  This partial parser is more complex than a typical handwritten
  parser. If you are unfamiliar with handwritten JSON parsers, you may
  want to take a look
  at &lt;a href="https://notes.eatonphil.com/tags/json.html"&gt;previous
  articles&lt;/a&gt; I've written about parsing JSON.
&lt;/p&gt;&lt;p&gt;Once we get this partial parser working we'll turn to Go's builtin
profiler to find what we can do to make it faster.&lt;/p&gt;
&lt;p&gt;All code for this post is &lt;a href="https://github.com/eatonphil/jqgo"&gt;available on
Github&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="machine-specs,-versions"&gt;Machine specs, versions&lt;/h3&gt;&lt;p&gt;Since we're going to be doing some rudimentary comparisons of
performance, here are my details. I am running everything on a
dedicated server, &lt;a href="https://us.ovhcloud.com/bare-metal/rise/rise-1/"&gt;OVH
Rise-1&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RAM: 64 GB DDR4 ECC 2,133 MHz&lt;/li&gt;
&lt;li&gt;Disk: 2x450 GB SSD NVMe in Soft RAID&lt;/li&gt;
&lt;li&gt;Processor: Intel Xeon E3-1230v6 - 4c/8t - 3.5 GHz/3.9 GHz&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And relevant versions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;--version
jq-1.6
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;version
go&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;go1.18&lt;span class="w"&gt; &lt;/span&gt;linux/amd64
$&lt;span class="w"&gt; &lt;/span&gt;uname&lt;span class="w"&gt; &lt;/span&gt;-a
Linux&lt;span class="w"&gt; &lt;/span&gt;phil&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;.18.10-100.fc35.x86_64&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#1 SMP PREEMPT_DYNAMIC Thu Jul 7 17:41:37 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now buckle up!&lt;/p&gt;
&lt;h3 id="jq-using-go's-builtin-json-library"&gt;jq using Go's builtin JSON library&lt;/h3&gt;&lt;p&gt;This is a very simple program. We just parse JSON data from stdin in a
loop. And after parsing each time we'll call a &lt;code&gt;extractValueAtPath&lt;/code&gt;
function to grab the value at the path the user asks for.&lt;/p&gt;
&lt;p&gt;To keep our path "parser" very simple we'll treat array access the
same as object access. So we'll look for &lt;code&gt;x.0&lt;/code&gt; instead of &lt;code&gt;x[0]&lt;/code&gt;,
unlike jq.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;io&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;strconv&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;strings&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;extractValueAtPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// TODO&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;enc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EOF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;extractValueAtPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;enc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we implement the &lt;code&gt;extractValueAtPath&lt;/code&gt; function itself,
entering into JSON arrays and objects until we reach the end of the
path.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;extractValueAtPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.([]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Path into a non-map&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Path does not exist&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Alright, let's give it a go module and build and run it!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;mod&lt;span class="w"&gt; &lt;/span&gt;init&lt;span class="w"&gt; &lt;/span&gt;control
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;mod&lt;span class="w"&gt; &lt;/span&gt;tidy
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
&lt;span class="c1"&gt;# Grab a test file&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;https://raw.githubusercontent.com/json-iterator/test-data/master/large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.[]'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;large-file.json
$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./control&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;
&lt;span class="s2"&gt;&amp;quot;https://api.github.com/repos/petroav/6.828&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;&amp;quot;https://api.github.com/repos/rspt/rspt-theme&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Sweet. Now let's make sure it produces the same thing as jq.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./control&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;control.test
$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jq.test
$&lt;span class="w"&gt; &lt;/span&gt;diff&lt;span class="w"&gt; &lt;/span&gt;jq.test&lt;span class="w"&gt; &lt;/span&gt;control.test
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Great! It's working for a basic query. Let's see how it performs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;hyperfine&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | ./control '.repo.url' &amp;gt; control.test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | jq '.repo.url' &amp;gt; jq.test&amp;quot;&lt;/span&gt;
Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./control&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;control.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;310&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;.4&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;296&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;49&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;296&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;344&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jq.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;355&lt;/span&gt;.8&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;348&lt;/span&gt;.8&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;27&lt;/span&gt;.7&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;354&lt;/span&gt;.8&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;358&lt;/span&gt;.5&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Summary
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | ./control '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; control.test'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ran
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.15&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.05&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;faster&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | jq '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; jq.test'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that's surprising! This naive implementation in Go is a bit faster
than standard jq. But our implementation supports a heck of a lot less
than jq. So this benchmark on its own isn't incredibly meaningful.&lt;/p&gt;
&lt;p&gt;However, it's a good base for comparing to our next implementation.&lt;/p&gt;
&lt;p class="note"&gt;
  Astute readers may notice that this version doesn't use a buffered
  reader from stdin, while the next version will. I tried this version
  with and without wrapping stdin in a buffered reader but it didn't
  make a meaningful difference. It might be because Go's JSON decoder
  does its own buffering. I'm not sure.
&lt;/p&gt;&lt;p&gt;Let's do the fun implementation.&lt;/p&gt;
&lt;h3 id="partial-parsing"&gt;Partial parsing&lt;/h3&gt;&lt;p&gt;Unlike a typical handwritten parser this partial parser is going to
contain almost two parsers. One parser will care exactly about the
structure of JSON. The other parser will only care about reading past
the current value (whether it be a number or string or array or
object, etc.) The path we pass to the parser will be used to decide
whether each value should be fully parsed or partially parsed.&lt;/p&gt;
&lt;p class="note"&gt;
  I'll reiterate: this partial parser is more complex than a typical
  handwritten parser. If you are unfamiliar with handwritten JSON
  parsers, you may want to take a look
  at &lt;a href="https://notes.eatonphil.com/tags/json.html"&gt;previous
  articles&lt;/a&gt; I've written about parsing JSON.
&lt;/p&gt;&lt;p&gt;The shell of this partial parser is going to look similar to the shell
of the first parser.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bufio&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;io&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;strconv&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;strings&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IMPLEMENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;enc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extractDataFromJsonPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EOF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Read&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatalln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;enc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatalln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Except instead of using the builtin JSON parser we'll call our own
&lt;code&gt;extractDataFromJsonPath&lt;/code&gt; function that handles parsing and extraction
all at once.&lt;/p&gt;
&lt;p&gt;Before doing that we'll add a few helper functions. The first one grabs
a byte from a reader and stores the read byte locally (so we can print
out all read bytes if the program fails).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReadByte&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;reset&lt;/code&gt; member zeroes out the &lt;code&gt;read&lt;/code&gt; bytes and gets called before
each object is parsed in the &lt;code&gt;main&lt;/code&gt; main loop.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let's get into &lt;code&gt;extractDataFromJsonPath&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="extractdatafromjsonpath"&gt;extractDataFromJsonPath&lt;/h3&gt;&lt;p&gt;This is the real parser. It expects a JSON object and fully parses the
object, almost.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;extractDataFromJsonPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Make sure we're actually going into an object&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'{'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected opening curly brace, got: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// We found the end of the object&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'}'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Key-value pairs must be separated by commas&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected comma between key-value pairs, got: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Grab the key&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Find a colon separating key from value&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;':'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected colon, got: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Up to this point it looks like any old handwritten parser. There are a
few helpers in there (&lt;code&gt;eatWhitespace&lt;/code&gt;, &lt;code&gt;expectString&lt;/code&gt;) we'll implement
shortly.&lt;/p&gt;
&lt;p&gt;But once we see each key and are ready to look for a value we can
decide if we need to fully parse the value (if the path goes into this
key) or if we can partially parse the value (because the path does not
go into this key).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// If the key is not the start of this path, skip past this value&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Otherwise this is a path we want, grab the value&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that's it! The core parsing loop is done. The meat now becomes 1)
the &lt;code&gt;eatValue&lt;/code&gt; function that partially parses JSON and 2) the
&lt;code&gt;expectValue&lt;/code&gt; function that either encounters a scalar value and
returns it or recursively calls &lt;code&gt;extractDataFromJsonPath&lt;/code&gt; to enter some new object.&lt;/p&gt;
&lt;h4 id="notes-on-helper-naming"&gt;Notes on helper naming&lt;/h4&gt;&lt;p&gt;There are three main kinds of helpers you'll see. &lt;code&gt;expectX&lt;/code&gt; helpers
like &lt;code&gt;expectString&lt;/code&gt; will return early with an error if they fail to
find what they're looking for. &lt;code&gt;eatX&lt;/code&gt; helpers like &lt;code&gt;eatWhitespace&lt;/code&gt;
will not return any value and will only move the read cursor
forward. And &lt;code&gt;tryX&lt;/code&gt; helpers like &lt;code&gt;tryNumber&lt;/code&gt; will do the same thing as
&lt;code&gt;expectString&lt;/code&gt; but return an additional boolean argument. So the
caller can decide whether or not to make other attempts at parsing.&lt;/p&gt;
&lt;p&gt;But first let's fill in the two helpers we skipped. First off, &lt;code&gt;eatWhitespace&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="eatwhitespace"&gt;eatWhitespace&lt;/h3&gt;&lt;p&gt;This function peeks and reads bytes while the bytes are whitespace.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;isWhitespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\t'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\r'&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isWhitespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it! Next we need to fill in &lt;code&gt;expectString&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="expectstring"&gt;expectString&lt;/h3&gt;&lt;p&gt;This is a standard handwritten parser helper that looks for a
double quote and keeps collecting bytes until it finds an ending
double quote that is not escaped.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expectString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bufio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Look&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;opening&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Expected double quote to start string, got: '&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Overwrite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;escaped&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;quot;'&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Otherwise&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="s1"&gt;'s the actual end&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Standard stuff! Now let's get back to those meaty functions we
introduced before, starting with &lt;code&gt;expectValue&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="expectvalue"&gt;expectValue&lt;/h3&gt;&lt;p&gt;This function is called by &lt;code&gt;extractDataFromJsonPath&lt;/code&gt; when it wants to
fully parse a value.&lt;/p&gt;
&lt;p&gt;If we see a left curly brace, we call &lt;code&gt;extractDataFromJsonPath&lt;/code&gt; with
it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;expectValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'{'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extractDataFromJsonPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Otherwise if we see a left bracket we call a new helper
&lt;code&gt;extractArrayDataFromJsonPath&lt;/code&gt; which will be almost identical to
&lt;code&gt;extractDataFromJsonPath&lt;/code&gt; but for parsing array syntax.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'['&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extractArrayDataFromJsonPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the value we're trying to parse isn't an array or object and
there's more of a path then we have to return null because we can't
enter into a scalar value.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Can't go any further into a path&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Reached the end of this object but more of&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// the path remains. So this object doesn't&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// contain this path.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we try to parse a scalar (numbers, strings, booleans, &lt;code&gt;null&lt;/code&gt;) and
ultimately return an error if nothing worked.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tryScalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected scalar, got: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's implement &lt;code&gt;tryScalar&lt;/code&gt; and its dependencies now. And we'll come
back to &lt;code&gt;extractArrayDataFromJsonPath&lt;/code&gt; afterward.&lt;/p&gt;
&lt;h3 id="tryscalar"&gt;tryScalar&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;tryScalar&lt;/code&gt; is similar to &lt;code&gt;expectValue&lt;/code&gt;. It's called &lt;code&gt;tryScalar&lt;/code&gt;
because it's allowed to fail.&lt;/p&gt;
&lt;p&gt;We peek at the first byte and switch on a dedicated parsing helper
based on it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tryScalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'t'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'f'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'n'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;null&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tryNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This passes control flow to two new functions, &lt;code&gt;expectIdentifier&lt;/code&gt; and
&lt;code&gt;tryNumber&lt;/code&gt;. Let's do &lt;code&gt;expectIdentifier&lt;/code&gt; next.&lt;/p&gt;
&lt;h3 id="expectidentifier"&gt;expectIdentifier&lt;/h3&gt;&lt;p&gt;This function tries to match the reader on a string passed to it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;expectIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ident&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReadByte&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ident&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown value: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  Thanks &lt;a href="https://twitter.com/deliberatecoder"&gt;Michael
  Lynch&lt;/a&gt; for pointing out in an earlier version that
  &lt;code&gt;expectIdentifier&lt;/code&gt; does not need to &lt;code&gt;Peek&lt;/code&gt;/&lt;code&gt;Discard&lt;/code&gt; but can just
  &lt;code&gt;ReadByte&lt;/code&gt; instead.
&lt;/p&gt;&lt;h3 id="trynumber"&gt;tryNumber&lt;/h3&gt;&lt;p&gt;This function tries to parse a number. We'll do a very lazy number
parser that will &lt;em&gt;most likely&lt;/em&gt; allow all valid numbers. Internally
we'll call &lt;code&gt;json.Unmarshal&lt;/code&gt; on the bytes we build up to do the
conversion itself.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tryNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bufio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb nb-Type"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;characters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;isNumberCharacter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'9'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'e'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isNumberCharacter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we can't find a number, that's ok. We'll just say so in the first
argument by returning &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="outstanding-functions"&gt;Outstanding functions&lt;/h3&gt;&lt;p&gt;Ok we've come a while building out helper functions. The last two
remaining helpers are &lt;code&gt;extractArrayDataFromJsonPath&lt;/code&gt; and
&lt;code&gt;eatValue&lt;/code&gt;. Let's finish up these real parser functions before getting
to &lt;code&gt;eatValue&lt;/code&gt;, the primary partial parsing function.&lt;/p&gt;
&lt;h3 id="extractarraydatafromjsonpath"&gt;extractArrayDataFromJsonPath&lt;/h3&gt;&lt;p&gt;This function is almost identical to &lt;code&gt;extractDataFromJsonPath&lt;/code&gt; but
rather than parsing key-value pairs inside curly braces it parses
values inside brackets.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;extractArrayDataFromJsonPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Path inside an array must be an integer&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Look for opening bracket. Make sure we're in an array&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'['&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected opening bracket, got: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Found closing bracket, exit the array&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;']'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Array values must be separated by a comma&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected comma between key-value pairs, got: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just like &lt;code&gt;extractDataFromJsonPath&lt;/code&gt; it either calls &lt;code&gt;eatValue&lt;/code&gt; or
&lt;code&gt;expectValue&lt;/code&gt; depending on whether the current index matches the
requested path.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// If the key is not the start of this path, skip past this value&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it for full parser functions! Let's do the partial parser,
&lt;code&gt;eatValue&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="eatvalue"&gt;eatValue&lt;/h3&gt;&lt;p&gt;This function is simpler than the full parser functions we wrote
before.&lt;/p&gt;
&lt;p&gt;First off it looks for the simple case where the value is a scalar.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eatValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bufio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;inString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryScalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;was&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;we&lt;/span&gt;&lt;span class="s1"&gt;'re done!&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All it does is read until the value ends.&lt;/p&gt;
&lt;p&gt;If the value is not a scalar though we need to read past complete JSON
arrays and/or objects.&lt;/p&gt;
&lt;p&gt;To do this we'll simply read through bytes, monitoring a stack of
open and close braces and brackets. If we enter a string we'll skip
all bytes inside the string until the string ends.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Otherwise it's an array or object&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;inString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Two \\-es cancel eachother out&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'['&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;']'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'['&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unexpected end of array: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'{'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'}'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'{'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unexpected end of object: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;inString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Closing quote case handled elsewhere, above&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we're finally done the first pass of the path-aware jq
implementation.&lt;/p&gt;
&lt;h3 id="build,-test,-benchmark"&gt;Build, test, benchmark&lt;/h3&gt;&lt;p&gt;Let's give it a go module, build and test it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;mod&lt;span class="w"&gt; &lt;/span&gt;init&lt;span class="w"&gt; &lt;/span&gt;jqgo
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;https://raw.githubusercontent.com/json-iterator/test-data/master/large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.[]'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;large-file.json
$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./jqgo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jqgo.test
$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jq.test
$&lt;span class="w"&gt; &lt;/span&gt;diff&lt;span class="w"&gt; &lt;/span&gt;jq.test&lt;span class="w"&gt; &lt;/span&gt;jqgo.test
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Great! :) Let's benchmark it against jq and the control
implementation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;hyperfine&lt;span class="w"&gt; &lt;/span&gt;--warmup&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | ./control/control '.repo.url' &amp;gt; control.test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | ./jqgo '.repo.url' &amp;gt; jqgo.test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | jq '.repo.url' &amp;gt; jq.test&amp;quot;&lt;/span&gt;
Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./control/control&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;control.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;302&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.4&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;283&lt;/span&gt;.7&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;53&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;297&lt;/span&gt;.4&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;309&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./jqgo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jqgo.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;258&lt;/span&gt;.8&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;230&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;47&lt;/span&gt;.6&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;256&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;262&lt;/span&gt;.6&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jq.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;357&lt;/span&gt;.6&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;350&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;28&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;355&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;362&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Summary
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | ./jqgo '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; jqgo.test'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ran
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.17&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.02&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;faster&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | ./control/control '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; control.test'&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.38&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.02&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;faster&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | jq '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; jq.test'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now to my surprise we're already beating the non-path-aware control
implementation! When I first wrote the path-aware version, it was
slower than the control. So I had to start performance profiling. For
this blog post I tried to remake the slowest variation I could
remember but I couldn't get it slower than this.&lt;/p&gt;
&lt;p&gt;That said, the best version &lt;em&gt;was&lt;/em&gt; faster than this so I &lt;em&gt;can&lt;/em&gt;
demonstrate the process of profiling to improve performance.&lt;/p&gt;
&lt;p&gt;Let's dig in. :)&lt;/p&gt;
&lt;h3 id="profiling-in-go"&gt;Profiling in Go&lt;/h3&gt;&lt;p&gt;There are various ways to enable profiling in Go. One way some people
recommend is through the &lt;a href="https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go"&gt;builtin benchmark
support&lt;/a&gt;
in &lt;code&gt;go test&lt;/code&gt;. I don't really like this method though. I prefer to use
&lt;a href="https://github.com/pkg/profile"&gt;pkg/profile&lt;/a&gt; manually in &lt;code&gt;main.go&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gu"&gt;@@ -9,6 +9,8 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;       &amp;quot;os&amp;quot;
&lt;span class="w"&gt; &lt;/span&gt;       &amp;quot;strconv&amp;quot;
&lt;span class="w"&gt; &lt;/span&gt;       &amp;quot;strings&amp;quot;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="gi"&gt;+       &amp;quot;github.com/pkg/profile&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;)

&lt;span class="w"&gt; &lt;/span&gt;type jsonReader struct {
&lt;span class="gu"&gt;@@ -450,6 +452,7 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;}

&lt;span class="w"&gt; &lt;/span&gt;func main() {
&lt;span class="gi"&gt;+       defer profile.Start().Stop()&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;       path := strings.Split(os.Args[1], &amp;quot;.&amp;quot;)
&lt;span class="w"&gt; &lt;/span&gt;       if path[0] == &amp;quot;&amp;quot; {
&lt;span class="w"&gt; &lt;/span&gt;               path = path[1:]
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Build and run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;mod&lt;span class="w"&gt; &lt;/span&gt;tidy
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./jqgo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null
&lt;span class="m"&gt;2022&lt;/span&gt;/07/11&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:38:57&lt;span class="w"&gt; &lt;/span&gt;profile:&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;profiling&lt;span class="w"&gt; &lt;/span&gt;enabled,&lt;span class="w"&gt; &lt;/span&gt;/tmp/profile3691177944/cpu.pprof
&lt;span class="m"&gt;2022&lt;/span&gt;/07/11&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:38:58&lt;span class="w"&gt; &lt;/span&gt;profile:&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;profiling&lt;span class="w"&gt; &lt;/span&gt;disabled,&lt;span class="w"&gt; &lt;/span&gt;/tmp/profile3691177944/cpu.pprof
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go can &lt;a href="https://www.honeycomb.io/blog/golang-observability-using-the-new-pprof-web-ui-to-debug-memory-usage/"&gt;run a web
server&lt;/a&gt;
to visualize the pprof results but I find (after literally a few years
of trying to figure it out) the CLI makes more sense to me.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pprof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;profile3691177944&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pprof&lt;/span&gt;
&lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jqgo&lt;/span&gt;
&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;
&lt;span class="nx"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Jul&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="nx"&gt;am&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;401.63&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;samples&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;67.23&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;Entering&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;interactive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;o&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pprof&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we run &lt;code&gt;top10&lt;/code&gt; to see where we spend the bulk of time.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pprof&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;top10&lt;/span&gt;
&lt;span class="nx"&gt;Showing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;accounting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;
&lt;span class="nx"&gt;Showing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;flat&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;flat&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;cum&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;cum&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;34.62&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;34.62&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;230&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;88.46&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eatValue&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;23.08&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;57.69&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;26.92&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;19.23&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;76.92&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;23.08&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;7.69&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;84.62&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;7.69&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;syscall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Syscall&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;88.46&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Buffered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;92.31&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;readByte&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;96.15&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slicebytetostring&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stkbucket&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;fill&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mf"&gt;3.85&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Encoder&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now this is weird. Why are &lt;code&gt;Peek&lt;/code&gt; and &lt;code&gt;Discard&lt;/code&gt; so expensive? And why
are we spending so much time in &lt;code&gt;syscall.Syscall&lt;/code&gt;? The entire point of
buffered I/O is to avoid hitting syscalls too frequently.&lt;/p&gt;
&lt;p&gt;But since 88% of time is spent in &lt;code&gt;eatValue&lt;/code&gt;, let's verify where in
&lt;code&gt;eatValue&lt;/code&gt; we are spending that time.&lt;/p&gt;
&lt;p&gt;Within the &lt;code&gt;pprof&lt;/code&gt; REPL we can enter &lt;code&gt;list X&lt;/code&gt; where &lt;code&gt;X&lt;/code&gt; is a regexp of
a function name.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pprof&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eatValue&lt;/span&gt;
&lt;span class="nx"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;
&lt;span class="nx"&gt;ROUTINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;========================&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;eatValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;jqgo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;mainprof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;230&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;88.46&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Total&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;159&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;161&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;163&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;164&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tryScalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;165&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;166&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;167&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;168&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;169&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// It was a scalar, we're done!&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;170&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;171&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;172&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;173&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;174&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// Otherwise it's an array or object&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;175&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;176&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;177&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;178&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;179&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;181&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;182&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;183&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;184&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;185&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;186&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;187&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;188&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nx"&gt;inString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;189&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;190&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;191&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="c1"&gt;// Two \\-es cancel eachother out&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;192&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;193&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;194&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;195&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;196&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;197&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;198&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;199&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;203&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'['&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;205&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;']'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;206&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;207&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;208&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'['&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;209&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unexpected end of array: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;210&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;211&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'{'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;212&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;213&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'}'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;214&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;215&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;216&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'{'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;217&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unexpected end of object: '%s'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;218&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;219&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So by rank we can see we do spend the most time in &lt;code&gt;Peek&lt;/code&gt; and
&lt;code&gt;Discard&lt;/code&gt;. Then in pulling the last item out of the stack??? That's
weird. Let's ignore that.&lt;/p&gt;
&lt;h3 id="peek-and-discard"&gt;Peek and Discard&lt;/h3&gt;&lt;p&gt;Let's look at &lt;code&gt;Peek&lt;/code&gt; in the pprof REPL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pprof&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;
&lt;span class="nx"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;
&lt;span class="nx"&gt;ROUTINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;========================&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;26.92&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Total&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;130&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;// also returns an error explaining why the read is short. The error is&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;131&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;// ErrBufferFull if n is larger than b's buffer size.&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;132&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;133&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;// Calling Peek prevents a UnreadByte or UnreadRune call from succeeding&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;134&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;// until the next read operation.&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;135&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;136&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;137&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrNegativeCount&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;138&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;139&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;140&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastByte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;141&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastRuneSize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;142&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;143&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;144&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// b.w-b.r &amp;lt; len(b.buf) =&amp;gt; buffer is not full&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;145&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;146&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;147&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;148&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrBufferFull&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;149&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;151&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;// 0 &amp;lt;= n &amp;lt;= len(b.buf)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;152&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;153&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;avail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;avail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;154&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;// not enough data in buffer&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;155&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;avail&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;156&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readErr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;157&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;158&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ErrBufferFull&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;159&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;161&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;162&lt;/span&gt;&lt;span class="p"&gt;:}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;163&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;164&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;// Discard skips the next n bytes, returning the number of bytes discarded.&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;165&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;166&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;// If Discard skips fewer than n bytes, it also returns an error.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The bulk of time here is spent in refilling the buffer (the &lt;code&gt;fill&lt;/code&gt;
method). So it seems like while &lt;code&gt;bufio.Reader&lt;/code&gt; buffers &lt;em&gt;reads&lt;/em&gt; it
basically seems to not buffer &lt;em&gt;peeks&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But hey, we were peeking and discarding one at a time anyway. Peeking
and discarding were the same cost in &lt;code&gt;eatValue&lt;/code&gt;. So let's ignore
peeking for a second and think about discarding.&lt;/p&gt;
&lt;p&gt;We could avoid doing so many discards if we just keep track of how
much we are peeking at in the loop and only discard once at the end of
the loop. (As an implementation detail, since there's a max internal
buffer size we'll need to actually periodically discard when we try to
peek and get a "buffer full" error.)&lt;/p&gt;
&lt;p&gt;And based on that &lt;code&gt;top10&lt;/code&gt; result above, we need to do this in
&lt;code&gt;eatValue&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gu"&gt;@@ -170,16 +170,31 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;       }

&lt;span class="w"&gt; &lt;/span&gt;       // Otherwise it's an array or object
&lt;span class="gi"&gt;+       length := 0&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;       first := true
&lt;span class="gd"&gt;-&lt;/span&gt;
&lt;span class="gi"&gt;+       var bs []byte&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;       for first || len(stack) &amp;gt; 0 {
&lt;span class="gi"&gt;+               length++&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;               first = false

&lt;span class="gd"&gt;-               bs, err := r.Peek(1)&lt;/span&gt;
&lt;span class="gd"&gt;-               if err != nil {&lt;/span&gt;
&lt;span class="gd"&gt;-                       return err&lt;/span&gt;
&lt;span class="gi"&gt;+               for {&lt;/span&gt;
&lt;span class="gi"&gt;+                       bs, err = r.Peek(length)&lt;/span&gt;
&lt;span class="gi"&gt;+                       if err == bufio.ErrBufferFull {&lt;/span&gt;
&lt;span class="gi"&gt;+                               _, err = r.Discard(length - 1)&lt;/span&gt;
&lt;span class="gi"&gt;+                               if err != nil {&lt;/span&gt;
&lt;span class="gi"&gt;+                                       return err&lt;/span&gt;
&lt;span class="gi"&gt;+                               }&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="gi"&gt;+                               length = 1&lt;/span&gt;
&lt;span class="gi"&gt;+                               continue&lt;/span&gt;
&lt;span class="gi"&gt;+                       }&lt;/span&gt;
&lt;span class="gi"&gt;+                       if err != nil {&lt;/span&gt;
&lt;span class="gi"&gt;+                               return err&lt;/span&gt;
&lt;span class="gi"&gt;+                       }&lt;/span&gt;
&lt;span class="gi"&gt;+&lt;/span&gt;
&lt;span class="gi"&gt;+                       break&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;               }
&lt;span class="gd"&gt;-               b := bs[0]&lt;/span&gt;
&lt;span class="gi"&gt;+               b := bs[length-1]&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;               if inString {
&lt;span class="w"&gt; &lt;/span&gt;                       if b == '&amp;quot;' &amp;amp;&amp;amp; prev != '\\' {
&lt;span class="gu"&gt;@@ -193,7 +208,6 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;                               prev = b
&lt;span class="w"&gt; &lt;/span&gt;                       }

&lt;span class="gd"&gt;-                       r.Discard(1)&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;                       continue
&lt;span class="w"&gt; &lt;/span&gt;               }

&lt;span class="gu"&gt;@@ -219,11 +233,11 @@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;                       // Closing quote case handled elsewhere, above
&lt;span class="w"&gt; &lt;/span&gt;               }

&lt;span class="gd"&gt;-               r.Discard(1)&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;               prev = b
&lt;span class="w"&gt; &lt;/span&gt;       }

&lt;span class="gd"&gt;-       return nil&lt;/span&gt;
&lt;span class="gi"&gt;+       _, err = r.Discard(length)&lt;/span&gt;
&lt;span class="gi"&gt;+       return err&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;}

&lt;span class="w"&gt; &lt;/span&gt;func (jr *jsonReader) tryScalar(r *bufio.Reader) (bool, any, error) {
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Comment out the &lt;code&gt;pkg/profile&lt;/code&gt; bits (profiling slows the whole thing down), rebuild, and rerun:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;hyperfine&lt;span class="w"&gt; &lt;/span&gt;--warmup&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | ./control/control '.repo.url' &amp;gt; control.test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | ./jqgo '.repo.url' &amp;gt; jqgo.test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | jq '.repo.url' &amp;gt; jq.test&amp;quot;&lt;/span&gt;
Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./control/control&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;control.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;302&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;287&lt;/span&gt;.7&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;49&lt;/span&gt;.7&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;296&lt;/span&gt;.6&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;308&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./jqgo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jqgo.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;215&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.6&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;189&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;46&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;213&lt;/span&gt;.5&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;218&lt;/span&gt;.7&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jq.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;355&lt;/span&gt;.7&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.4&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;349&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;26&lt;/span&gt;.4&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;354&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;359&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Summary
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | ./jqgo '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; jqgo.test'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ran
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.40&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.02&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;faster&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | ./control/control '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; control.test'&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.65&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.01&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;faster&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | jq '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; jq.test'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Great! We've shaved off another 40ms. Let's enable profiling,
re-run the program and go back into the pprof REPL.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./jqgo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null
&lt;span class="m"&gt;2022&lt;/span&gt;/07/11&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;03&lt;/span&gt;:12:07&lt;span class="w"&gt; &lt;/span&gt;profile:&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;profiling&lt;span class="w"&gt; &lt;/span&gt;enabled,&lt;span class="w"&gt; &lt;/span&gt;/tmp/profile2229743747/cpu.pprof
&lt;span class="m"&gt;2022&lt;/span&gt;/07/11&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;03&lt;/span&gt;:12:07&lt;span class="w"&gt; &lt;/span&gt;profile:&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;profiling&lt;span class="w"&gt; &lt;/span&gt;disabled,&lt;span class="w"&gt; &lt;/span&gt;/tmp/profile2229743747/cpu.pprof
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;tool&lt;span class="w"&gt; &lt;/span&gt;pprof&lt;span class="w"&gt; &lt;/span&gt;/tmp/profile2229743747/cpu.pprof
File:&lt;span class="w"&gt; &lt;/span&gt;jqgo
Type:&lt;span class="w"&gt; &lt;/span&gt;cpu
Time:&lt;span class="w"&gt; &lt;/span&gt;Jul&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2022&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;:12am&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;UTC&lt;span class="o"&gt;)&lt;/span&gt;
Duration:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;401&lt;/span&gt;.33ms,&lt;span class="w"&gt; &lt;/span&gt;Total&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;samples&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;210ms&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;52&lt;/span&gt;.33%&lt;span class="o"&gt;)&lt;/span&gt;
Entering&lt;span class="w"&gt; &lt;/span&gt;interactive&lt;span class="w"&gt; &lt;/span&gt;mode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;commands,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;o&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;options&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;pprof&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;top10
Showing&lt;span class="w"&gt; &lt;/span&gt;nodes&lt;span class="w"&gt; &lt;/span&gt;accounting&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;210ms,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;210ms&lt;span class="w"&gt; &lt;/span&gt;total
Showing&lt;span class="w"&gt; &lt;/span&gt;top&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nodes&lt;span class="w"&gt; &lt;/span&gt;out&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;flat&lt;span class="w"&gt;  &lt;/span&gt;flat%&lt;span class="w"&gt;   &lt;/span&gt;sum%&lt;span class="w"&gt;        &lt;/span&gt;cum&lt;span class="w"&gt;   &lt;/span&gt;cum%
&lt;span class="w"&gt;     &lt;/span&gt;100ms&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;47&lt;/span&gt;.62%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;47&lt;/span&gt;.62%&lt;span class="w"&gt;      &lt;/span&gt;180ms&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;85&lt;/span&gt;.71%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.eatValue
&lt;span class="w"&gt;      &lt;/span&gt;70ms&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;33&lt;/span&gt;.33%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;.95%&lt;span class="w"&gt;       &lt;/span&gt;70ms&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;33&lt;/span&gt;.33%&lt;span class="w"&gt;  &lt;/span&gt;bufio.&lt;span class="o"&gt;(&lt;/span&gt;*Reader&lt;span class="o"&gt;)&lt;/span&gt;.Peek
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;85&lt;/span&gt;.71%&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt;  &lt;/span&gt;encoding/json.&lt;span class="o"&gt;(&lt;/span&gt;*encodeState&lt;span class="o"&gt;)&lt;/span&gt;.string
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;90&lt;/span&gt;.48%&lt;span class="w"&gt;       &lt;/span&gt;20ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.52%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.expectString
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;95&lt;/span&gt;.24%&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.readByte
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;%&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt;  &lt;/span&gt;reflect.Value.Type
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;%&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;%&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt;  &lt;/span&gt;encoding/json.&lt;span class="o"&gt;(&lt;/span&gt;*Encoder&lt;span class="o"&gt;)&lt;/span&gt;.Encode
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;%&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;%&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt;  &lt;/span&gt;encoding/json.&lt;span class="o"&gt;(&lt;/span&gt;*decodeState&lt;span class="o"&gt;)&lt;/span&gt;.literalStore
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;%&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;%&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt;  &lt;/span&gt;encoding/json.&lt;span class="o"&gt;(&lt;/span&gt;*decodeState&lt;span class="o"&gt;)&lt;/span&gt;.unmarshal
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;%&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;%&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.76%&lt;span class="w"&gt;  &lt;/span&gt;encoding/json.&lt;span class="o"&gt;(&lt;/span&gt;*decodeState&lt;span class="o"&gt;)&lt;/span&gt;.value
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nice, &lt;code&gt;syscall.Syscall&lt;/code&gt; is no longer in the top 10. But &lt;code&gt;eatValue&lt;/code&gt; is
and we're still spending a bunch of time in &lt;code&gt;Peek&lt;/code&gt;. We didn't try to
stop calling &lt;code&gt;Peek&lt;/code&gt; so much, we just cut down on calling &lt;code&gt;Discard&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;List &lt;code&gt;eatValue&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;pprof&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;eatValue
Total:&lt;span class="w"&gt; &lt;/span&gt;210ms
&lt;span class="nv"&gt;ROUTINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;========================&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.eatValue&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/home/phil/tmp/jqgo/mainpeek.go
&lt;span class="w"&gt;     &lt;/span&gt;100ms&lt;span class="w"&gt;      &lt;/span&gt;180ms&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;flat,&lt;span class="w"&gt; &lt;/span&gt;cum&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;85&lt;/span&gt;.71%&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;Total
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;159&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;err&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jr.eatWhitespace&lt;span class="o"&gt;(&lt;/span&gt;r&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;160&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;err&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nil&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;161&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;err
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;162&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;163&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;       &lt;/span&gt;20ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;164&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;ok,&lt;span class="w"&gt; &lt;/span&gt;_,&lt;span class="w"&gt; &lt;/span&gt;err&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jr.tryScalar&lt;span class="o"&gt;(&lt;/span&gt;r&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;165&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;err&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nil&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;166&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;err
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;167&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;168&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;169&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;//&lt;span class="w"&gt; &lt;/span&gt;It&lt;span class="w"&gt; &lt;/span&gt;was&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;scalar,&lt;span class="w"&gt; &lt;/span&gt;we&lt;span class="s1"&gt;'re done!&lt;/span&gt;
&lt;span class="s1"&gt;         .          .    170:   if ok {&lt;/span&gt;
&lt;span class="s1"&gt;         .          .    171:           return nil&lt;/span&gt;
&lt;span class="s1"&gt;         .          .    172:   }&lt;/span&gt;
&lt;span class="s1"&gt;         .          .    173:&lt;/span&gt;
&lt;span class="s1"&gt;         .          .    174:   // Otherwise it'&lt;/span&gt;s&lt;span class="w"&gt; &lt;/span&gt;an&lt;span class="w"&gt; &lt;/span&gt;array&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;object
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;175&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;length&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;176&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;first&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;177&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;var&lt;span class="w"&gt; &lt;/span&gt;bs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;byte
&lt;span class="w"&gt;      &lt;/span&gt;20ms&lt;span class="w"&gt;       &lt;/span&gt;20ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;178&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;first&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;len&lt;span class="o"&gt;(&lt;/span&gt;stack&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;179&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;length++
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;180&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nv"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;181&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;182&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;20ms&lt;span class="w"&gt;       &lt;/span&gt;80ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;183&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;bs,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;r.Peek&lt;span class="o"&gt;(&lt;/span&gt;length&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;184&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bufio.ErrBufferFull&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;185&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;_,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;r.Discard&lt;span class="o"&gt;(&lt;/span&gt;length&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;186&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;err&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nil&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;187&lt;/span&gt;:&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;err
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;188&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;189&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;190&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;191&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;192&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;193&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;err&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nil&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;194&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;err
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;195&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;196&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;197&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;199&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;b&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bs&lt;span class="o"&gt;[&lt;/span&gt;length-1&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;:
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;201&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;inString&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;202&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;prev&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="m"&gt;203&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;inString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;204&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;205&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;206&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;//&lt;span class="w"&gt; &lt;/span&gt;Two&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;-es&lt;span class="w"&gt; &lt;/span&gt;cancel&lt;span class="w"&gt; &lt;/span&gt;eachother&lt;span class="w"&gt; &lt;/span&gt;out
&lt;span class="w"&gt;      &lt;/span&gt;20ms&lt;span class="w"&gt;       &lt;/span&gt;20ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;207&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;208&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;byte&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;210&lt;/span&gt;:&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;b
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;211&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The bulk of time is spent in &lt;code&gt;Peek&lt;/code&gt;. Let's list &lt;code&gt;Peek&lt;/code&gt; again.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;pprof&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;list&lt;span class="w"&gt; &lt;/span&gt;Peek
Total:&lt;span class="w"&gt; &lt;/span&gt;210ms
&lt;span class="nv"&gt;ROUTINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;========================&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bufio.&lt;span class="o"&gt;(&lt;/span&gt;*Reader&lt;span class="o"&gt;)&lt;/span&gt;.Peek&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/usr/local/go/src/bufio/bufio.go
&lt;span class="w"&gt;      &lt;/span&gt;70ms&lt;span class="w"&gt;       &lt;/span&gt;70ms&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;flat,&lt;span class="w"&gt; &lt;/span&gt;cum&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;33&lt;/span&gt;.33%&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;Total
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;130&lt;/span&gt;://&lt;span class="w"&gt; &lt;/span&gt;also&lt;span class="w"&gt; &lt;/span&gt;returns&lt;span class="w"&gt; &lt;/span&gt;an&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;explaining&lt;span class="w"&gt; &lt;/span&gt;why&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;short.&lt;span class="w"&gt; &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;is
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;131&lt;/span&gt;://&lt;span class="w"&gt; &lt;/span&gt;ErrBufferFull&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;larger&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;b&lt;span class="err"&gt;'&lt;/span&gt;s&lt;span class="w"&gt; &lt;/span&gt;buffer&lt;span class="w"&gt; &lt;/span&gt;size.
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;132&lt;/span&gt;://
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;133&lt;/span&gt;://&lt;span class="w"&gt; &lt;/span&gt;Calling&lt;span class="w"&gt; &lt;/span&gt;Peek&lt;span class="w"&gt; &lt;/span&gt;prevents&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;UnreadByte&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;UnreadRune&lt;span class="w"&gt; &lt;/span&gt;call&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;succeeding
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;134&lt;/span&gt;://&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;until&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;next&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;operation.
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;135&lt;/span&gt;:func&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;b&lt;span class="w"&gt; &lt;/span&gt;*Reader&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Peek&lt;span class="o"&gt;(&lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;int&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;([]&lt;/span&gt;byte,&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;136&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;137&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nil,&lt;span class="w"&gt; &lt;/span&gt;ErrNegativeCount
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;138&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;139&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;140&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;b.lastByte&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-1
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;141&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;b.lastRuneSize&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-1
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;142&lt;/span&gt;:
&lt;span class="w"&gt;      &lt;/span&gt;10ms&lt;span class="w"&gt;       &lt;/span&gt;10ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;143&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;b.w-b.r&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;b.w-b.r&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;len&lt;span class="o"&gt;(&lt;/span&gt;b.buf&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;b.err&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nil&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;144&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;b.fill&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;//&lt;span class="w"&gt; &lt;/span&gt;b.w-b.r&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;len&lt;span class="o"&gt;(&lt;/span&gt;b.buf&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;buffer&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;full
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;145&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;146&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;147&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;len&lt;span class="o"&gt;(&lt;/span&gt;b.buf&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;148&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;b.buf&lt;span class="o"&gt;[&lt;/span&gt;b.r:b.w&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;ErrBufferFull
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;149&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;150&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;151&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;//&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;len&lt;span class="o"&gt;(&lt;/span&gt;b.buf&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;152&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;var&lt;span class="w"&gt; &lt;/span&gt;err&lt;span class="w"&gt; &lt;/span&gt;error
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;153&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;avail&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;b.w&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;b.r&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;avail&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;154&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;//&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;enough&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;buffer
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;155&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;avail
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;156&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;b.readErr&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;157&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nil&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;158&lt;/span&gt;:&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ErrBufferFull
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;159&lt;/span&gt;:&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;160&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;50ms&lt;span class="w"&gt;       &lt;/span&gt;50ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;161&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;b.buf&lt;span class="o"&gt;[&lt;/span&gt;b.r&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;b.r+n&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;err
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;162&lt;/span&gt;:&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;163&lt;/span&gt;:
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;164&lt;/span&gt;://&lt;span class="w"&gt; &lt;/span&gt;Discard&lt;span class="w"&gt; &lt;/span&gt;skips&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;next&lt;span class="w"&gt; &lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;bytes,&lt;span class="w"&gt; &lt;/span&gt;returning&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;number&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;bytes&lt;span class="w"&gt; &lt;/span&gt;discarded.
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;165&lt;/span&gt;://
&lt;span class="w"&gt;         &lt;/span&gt;.&lt;span class="w"&gt;          &lt;/span&gt;.&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;166&lt;/span&gt;://&lt;span class="w"&gt; &lt;/span&gt;If&lt;span class="w"&gt; &lt;/span&gt;Discard&lt;span class="w"&gt; &lt;/span&gt;skips&lt;span class="w"&gt; &lt;/span&gt;fewer&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;bytes,&lt;span class="w"&gt; &lt;/span&gt;it&lt;span class="w"&gt; &lt;/span&gt;also&lt;span class="w"&gt; &lt;/span&gt;returns&lt;span class="w"&gt; &lt;/span&gt;an&lt;span class="w"&gt; &lt;/span&gt;error.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well it's not really clear to me from this why we spend so much time
slicing here.&lt;/p&gt;
&lt;p&gt;We might be able to use &lt;code&gt;Peek&lt;/code&gt; much less if we kept our own FIFO queue
of peeked-at bytes. But I don't feel like writing a correct, efficient
FIFO queue (a ring buffer, basically) and maybe there are other
aspects of this program we can look at. So let's give this train of
thought a break.&lt;/p&gt;
&lt;h3 id="memory-profiling"&gt;Memory profiling&lt;/h3&gt;&lt;p&gt;Let's change tactics entirely. Memory allocation tends to be
expensive. Allocating in a loop is generally a bad idea. And this
entire program is a loop. So let's try doing a memory profile instead
of a CPU profile.&lt;/p&gt;
&lt;p&gt;Instead of &lt;code&gt;defer profile.Start().Stop()&lt;/code&gt; we'll set &lt;code&gt;defer
profile.Start(profile.MemProfile).Stop()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Build, rerun and enter pprof with the &lt;code&gt;-alloc_space&lt;/code&gt; flag. We want to
see where memory is being allocated.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./jqgo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/null
&lt;span class="m"&gt;2022&lt;/span&gt;/07/11&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;03&lt;/span&gt;:24:55&lt;span class="w"&gt; &lt;/span&gt;profile:&lt;span class="w"&gt; &lt;/span&gt;memory&lt;span class="w"&gt; &lt;/span&gt;profiling&lt;span class="w"&gt; &lt;/span&gt;enabled&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;rate&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;/tmp/profile1407859643/mem.pprof
&lt;span class="m"&gt;2022&lt;/span&gt;/07/11&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;03&lt;/span&gt;:24:56&lt;span class="w"&gt; &lt;/span&gt;profile:&lt;span class="w"&gt; &lt;/span&gt;memory&lt;span class="w"&gt; &lt;/span&gt;profiling&lt;span class="w"&gt; &lt;/span&gt;disabled,&lt;span class="w"&gt; &lt;/span&gt;/tmp/profile1407859643/mem.pprof
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;tool&lt;span class="w"&gt; &lt;/span&gt;pprof&lt;span class="w"&gt; &lt;/span&gt;-alloc_objects&lt;span class="w"&gt; &lt;/span&gt;/tmp/profile1407859643/mem.pprof
File:&lt;span class="w"&gt; &lt;/span&gt;jqgo
Type:&lt;span class="w"&gt; &lt;/span&gt;alloc_objects
Time:&lt;span class="w"&gt; &lt;/span&gt;Jul&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2022&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;:24am&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;UTC&lt;span class="o"&gt;)&lt;/span&gt;
Entering&lt;span class="w"&gt; &lt;/span&gt;interactive&lt;span class="w"&gt; &lt;/span&gt;mode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;commands,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;o&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;options&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;pprof&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;top10
Showing&lt;span class="w"&gt; &lt;/span&gt;nodes&lt;span class="w"&gt; &lt;/span&gt;accounting&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;365899&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;99&lt;/span&gt;.95%&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;366086&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;total
Dropped&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nodes&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;cum&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1830&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
Showing&lt;span class="w"&gt; &lt;/span&gt;top&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nodes&lt;span class="w"&gt; &lt;/span&gt;out&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;flat&lt;span class="w"&gt;  &lt;/span&gt;flat%&lt;span class="w"&gt;   &lt;/span&gt;sum%&lt;span class="w"&gt;        &lt;/span&gt;cum&lt;span class="w"&gt;   &lt;/span&gt;cum%
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;227585&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;62&lt;/span&gt;.17%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;62&lt;/span&gt;.17%&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;262708&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;71&lt;/span&gt;.76%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.expectString
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;40945&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;.18%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;73&lt;/span&gt;.35%&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;40945&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;.18%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.readByte
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;39500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.79%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;84&lt;/span&gt;.14%&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;252585&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;69&lt;/span&gt;.00%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.tryScalar
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;30009&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.20%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;92&lt;/span&gt;.34%&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;41924&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;.45%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.tryNumber
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;12055&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.29%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;95&lt;/span&gt;.63%&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;215416&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;58&lt;/span&gt;.84%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.eatValue
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;7555&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.06%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;97&lt;/span&gt;.70%&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;11915&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.25%&lt;span class="w"&gt;  &lt;/span&gt;encoding/json.Unmarshal
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;4360&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.19%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;98&lt;/span&gt;.89%&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;4360&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.19%&lt;span class="w"&gt;  &lt;/span&gt;encoding/json.&lt;span class="o"&gt;(&lt;/span&gt;*decodeState&lt;span class="o"&gt;)&lt;/span&gt;.literalStore
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;3847&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.05%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;99&lt;/span&gt;.94%&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;3847&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.05%&lt;span class="w"&gt;  &lt;/span&gt;main.&lt;span class="o"&gt;(&lt;/span&gt;*jsonReader&lt;span class="o"&gt;)&lt;/span&gt;.expectIdentifier
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;43&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.012%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;99&lt;/span&gt;.95%&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;365931&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;%&lt;span class="w"&gt;  &lt;/span&gt;runtime.main
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;99&lt;/span&gt;.95%&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;4360&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.19%&lt;span class="w"&gt;  &lt;/span&gt;encoding/json.&lt;span class="o"&gt;(&lt;/span&gt;*decodeState&lt;span class="o"&gt;)&lt;/span&gt;.unmarshal
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And just like in the CPU profile we can list functions to see where
the allocations happen in code. Let's list the biggest memory user
here, &lt;code&gt;expectString&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pprof&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expectString&lt;/span&gt;
&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;366086&lt;/span&gt;
&lt;span class="n"&gt;ROUTINE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;========================&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;jqgo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mainpeek&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;227585&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;262708&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;71.76&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mi"&gt;4941&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Expected double quote to start string, got: '&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;30182&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;74&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;83&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Overwrite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;escaped&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;86&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;quot;'&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;87&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Otherwise&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="s1"&gt;'s the actual end&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;146302&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;146302&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;93&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;94&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;81283&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="mi"&gt;81283&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;97&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;:}&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expectIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bufio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the biggest offender is growing the string! The good thing is that
growing this string can be amortized because we can share the
underlying string memory across calls on the &lt;code&gt;jsonResponse&lt;/code&gt;
struct. This way, &lt;code&gt;expectString&lt;/code&gt; only needs to grow the string when it
actually sees a bigger string than we've already seen.&lt;/p&gt;
&lt;p&gt;The builtin &lt;a href="https://pkg.go.dev/bytes#Buffer"&gt;bytes.Buffer&lt;/a&gt; type does
exactly this. We can put a &lt;code&gt;bytes.Buffer&lt;/code&gt; on the &lt;code&gt;jsonResponse&lt;/code&gt; struct
because this code isn't multithreaded and because &lt;code&gt;expectString&lt;/code&gt;
doesn't call itself.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;@@&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@@&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bufio&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bytes&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;io&amp;quot;&lt;/span&gt;
&lt;span class="err"&gt;@@&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@@&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nx"&gt;expectString_buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;@@&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@@&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;expectString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectString_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eatWhitespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;@@&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@@&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// Overwrite the escaped double quote&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectString_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectString_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;// Otherwise it's the actual end&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectString_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectString_buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  Or instead of sharing memory on the struct, maybe this would be a
  good place to use &lt;a href="https://pkg.go.dev/sync#Pool"&gt;sync.Pool&lt;/a&gt;?
&lt;/p&gt;&lt;p&gt;Disable &lt;code&gt;pkg/profile&lt;/code&gt;, build and rerun with hyperfine.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;hyperfine&lt;span class="w"&gt; &lt;/span&gt;--warmup&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | ./control/control '.repo.url' &amp;gt; control.test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | ./jqgo '.repo.url' &amp;gt; jqgo.test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cat large-file.json | jq '.repo.url' &amp;gt; jq.test&amp;quot;&lt;/span&gt;
Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./control/control&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;control.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;307&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.8&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;292&lt;/span&gt;.8&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;49&lt;/span&gt;.4&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;296&lt;/span&gt;.5&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;326&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./jqgo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jqgo.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;210&lt;/span&gt;.8&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;185&lt;/span&gt;.4&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;44&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;216&lt;/span&gt;.8&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Benchmark&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;large-file.json&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.repo.url'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;jq.test
&lt;span class="w"&gt;  &lt;/span&gt;Time&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mean&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;σ&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;356&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.6&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;User:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;349&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms,&lt;span class="w"&gt; &lt;/span&gt;System:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;26&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Range&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;min&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;max&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;354&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt; &lt;/span&gt;…&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;362&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;ms&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;runs

Summary
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | ./jqgo '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; jqgo.test'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ran
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.46&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.05&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;faster&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | ./control/control '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; control.test'&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.69&lt;span class="w"&gt; &lt;/span&gt;±&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.02&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;faster&lt;span class="w"&gt; &lt;/span&gt;than&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'cat large-file.json | jq '&lt;/span&gt;.repo.url&lt;span class="s1"&gt;' &amp;gt; jq.test'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we've shaved another 20ms off. That's not bad!&lt;/p&gt;
&lt;h3 id="coming-to-a-close"&gt;Coming to a close&lt;/h3&gt;&lt;p&gt;There is more we could do but this is a long post already.&lt;/p&gt;
&lt;p&gt;For example, in the project repo I also built a &lt;a href="https://github.com/eatonphil/jqgo/blob/main/vector.go"&gt;generic vector
type&lt;/a&gt; with a
pop operation that is used for the stack in the &lt;code&gt;eatValue&lt;/code&gt;
function. It is shared on the &lt;code&gt;jsonReader&lt;/code&gt; instance like the
&lt;code&gt;expectString&lt;/code&gt; buffer. This ended up shaving another 20ms. And I also
got rid of most conversions from &lt;code&gt;[]byte&lt;/code&gt; to &lt;code&gt;string&lt;/code&gt; (which is an
expensive allocation you may notice listed as &lt;code&gt;bytes.String()&lt;/code&gt; in the
&lt;code&gt;top10&lt;/code&gt; of &lt;code&gt;-alloc_objects&lt;/code&gt; if you run the profiler again now.)&lt;/p&gt;
&lt;p&gt;But hopefully you're getting the gist of how you might investigate CPU
and memory usage. For me it's still a lot of poking around and trying
different things. But after a few years of trying to get better at
profiling Go programs I think I'm starting to get the hang of it.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I wrote a new blog post on implementing a simple jq clone from scratch in Go. This post explores partial/fuzzy parsing again and finishes with my approach to debugging memory/CPU usage in Go programs. It's a bit of a long post but hopefully worthwhile! :)&lt;a href="https://t.co/DxilIVaUBa"&gt;https://t.co/DxilIVaUBa&lt;/a&gt; &lt;a href="https://t.co/as3Sr5I2G0"&gt;pic.twitter.com/as3Sr5I2G0&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1546470283334270977?ref_src=twsrc%5Etfw"&gt;July 11, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 10 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/implementing-a-jq-clone-in-go.html</guid></item><item><title>Working Backwards</title><link>https://bytepawn.com/working-backwards.html</link><description>&lt;p&gt;Amazon established a set of principles and mechanisms, enabling the company to grow from a single founder to several hundred thousand employees while remaining stubbornly true to its mission of obsessing over customers to create long-term shareholder value.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Working Backwards" src="/images/working_backwards1.jpg" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 10 Jul 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/working-backwards.html</guid></item><item><title>DALL·E 2 - Selected works</title><link>https://smcleod.net/2022/07/dalle-2-selected-works/</link><description>&lt;p&gt;Over the past month I&amp;rsquo;ve been playing with OpenAI&amp;rsquo;s &lt;a href="https://openai.com/dall-e-2/"&gt;DALL·E 2&lt;/a&gt;, below are some of the  interesting images I&amp;rsquo;ve generated.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;&lt;em&gt;&lt;a href="https://openai.com/dall-e-2/"&gt;DALL·E 2&lt;/a&gt; is a new AI system that can create realistic images and art from a description in natural language.&lt;/em&gt;&amp;rdquo;&lt;/p&gt;
&lt;h2 id="a-renaissance-oil-painting-of-two-developers-arguing-over-which-javascript-framework-is-the-worst"&gt;&amp;ldquo;A renaissance oil painting of two developers arguing over which javascript framework is the worst&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2012.23.27%20-%20a%20renaissance%20oil%20painting%20of%20two%20developers%20arguing%20over%20which%20javascript%20framework%20is%20the%20worst.jpeg" /&gt;
&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2012.23.36%20-%20a%20renaissance%20oil%20painting%20of%20two%20developers%20arguing%20over%20which%20javascript%20framework%20is%20the%20worst.jpeg" /&gt;
&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2012.23.47%20-%20a%20renaissance%20oil%20painting%20of%20two%20developers%20arguing%20over%20which%20javascript%20framework%20is%20the%20worst.jpeg" /&gt;
&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2012.23.53%20-%20a%20renaissance%20oil%20painting%20of%20two%20developers%20arguing%20over%20which%20javascript%20framework%20is%20the%20worst.jpeg" /&gt;&lt;/p&gt;
&lt;h2 id="a-ralph-steadman-painting-of-7-cats-sitting-on-a-fence-and-one-raven"&gt;&amp;ldquo;A Ralph Steadman painting of 7 cats sitting on a fence, and one raven&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2015.36.13%20-%20A%20Ralph%20Steadman%20painting%20of%207%20cats%20sitting%20on%20a%20fence%2C%20and%20one%20raven.jpeg" /&gt;
&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2015.36.16%20-%20A%20Ralph%20Steadman%20painting%20of%207%20cats%20sitting%20on%20a%20fence%2C%20and%20one%20raven.jpeg" /&gt;
&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2015.36.21%20-%20A%20Ralph%20Steadman%20painting%20of%207%20cats%20sitting%20on%20a%20fence%2C%20and%20one%20raven.jpeg" /&gt;
&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2015.36.33%20-%20A%20Ralph%20Steadman%20painting%20of%207%20cats%20sitting%20on%20a%20fence%2C%20and%20one%20raven.jpeg" /&gt;
&lt;img src="https://media.githubusercontent.com/media/sammcj/smcleod_files_ml/main/dalle2/DALL%C2%B7E%202022-06-20%2015.36.37%20-%20A%20Ralph%20Steadman%20painting%20of%207%20cats%20sitting%20on%20a%20fence%2C%20and%20one%20raven.jpeg" /&gt;&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Fri, 08 Jul 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/07/dalle-2-selected-works/</guid></item><item><title>HBR Guide to Better Business Writing</title><link>https://bytepawn.com/hbr-guide-to-better-business-writing.html</link><description>&lt;p&gt;If your writing is sloppy and artless people will think you are the same. They won’t care about your message, they won’t do business with you. It’s not true that only ideas matter. Good writing gets ideas noticed.&lt;br /&gt;&lt;br /&gt; &lt;img alt="HBR Guide to Better Business Writing" src="/images/hbr_bbw.png" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 08 Jul 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/hbr-guide-to-better-business-writing.html</guid></item><item><title>Vim tip 11: replace characters in Normal mode</title><link>https://learnbyexample.github.io/tips/vim-tip-11/</link><description>&lt;p&gt;Often, you just need to change one character. For example, changing &lt;code&gt;i&lt;/code&gt; to &lt;code&gt;j&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt; to &lt;code&gt;4&lt;/code&gt;, &lt;code&gt;'&lt;/code&gt; to &lt;code&gt;&amp;quot;&lt;/code&gt; and so on.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;rj&lt;/kbd&gt; replace the character under the cursor with &lt;code&gt;j&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;ry&lt;/kbd&gt; replace the character under the cursor with &lt;code&gt;y&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;3ra&lt;/kbd&gt; replace the character under cursor as well as the two characters to the right with &lt;code&gt;aaa&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;no changes will be made if there aren't sufficient characters to match&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To replace multiple characters with different characters, use &lt;code&gt;R&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Rlion&lt;/kbd&gt; followed by &lt;kbd&gt;Esc&lt;/kbd&gt; replace the character under cursor and three characters to the right with &lt;code&gt;lion&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Esc&lt;/kbd&gt; key marks the completion of &lt;code&gt;R&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Backspace&lt;/kbd&gt; key will act as an undo command to give back the character that was replaced&lt;/li&gt;
&lt;li&gt;if you are replacing at the end of a line, the line will be automatically extended if needed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The advantage of &lt;code&gt;r&lt;/code&gt; and &lt;code&gt;R&lt;/code&gt; commands is that you remain in the Normal mode, without needing to switch to Insert mode and back.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 06 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-11/</guid></item><item><title>Moving to Source Hut</title><link>https://blog.bayindirh.io/blog/moving-to-source-hut/</link><description>&lt;p&gt;I have been &lt;a href="https://notes.bayindirh.io/notes/Lists/Discussions+about+Artificial+Intelligence"&gt;following&lt;/a&gt; the whole GitHub Copilot issue for a while, and I was not happy about Microsoft using open-source code hosted in GitHub without consent for training Copilot.&lt;/p&gt;
&lt;p&gt;Consent is only one part of a bigger issue though. As everybody knows, Microsoft has used open-source code on GitHub to train Copilot, disregarding the licenses. This means many repositories containing GPL licensed code have been used as well.&lt;/p&gt;
&lt;p&gt;Using GPL-licensed code in this manner is problematic on two fronts. The first is legal. GPL family of licenses doesn't allow source code to be closed. If you lift a function from a GPL-licensed codebase and integrate it into your code, you have to share your code under the same GPL license. The same is true for derivations of the code lifted from a GPL licensed codebase. However, Copilot disregards licenses on both ends while deriving code from its training set. It can start from a GPL function or mix GPL licensed code to a function licensed any other way. Since copilot is available to anyone, there's a serious risk of injecting GPL-licensed code into any codebase, regardless of license compatibility.&lt;/p&gt;
&lt;p&gt;This is a clear breach of the GPL license and is inexcusable.&lt;/p&gt;
&lt;p&gt;The second issue is ethical. Microsoft is not transparently communicating how they trained Copilot. They give vague answers and try to downplay the issue while denying all responsibility. See the second paragraph of this &lt;a href="https://docs.github.com/en/copilot/overview-of-github-copilot/about-github-copilot#using-github-copilot"&gt;document&lt;/a&gt;, which is quoted below:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You are responsible for ensuring the security and quality of your code. We recommend you take the same precautions when using code generated by GitHub Copilot that you would when using any code you didn't write yourself. These precautions include rigorous testing, IP scanning, and tracking for security vulnerabilities. GitHub provides a number of features to help you monitor and improve code quality, such as GitHub Actions, Dependabot, CodeQL and code scanning. All these features are free to use in public repositories. For more information, see "Understanding GitHub Actions" and "GitHub security features." &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However the issue is pretty serious to be downplayed. Copilot is a paid product, marketed to all developers writing all sorts of software. Using open-source code regardless of its license and giving it to anyone to do anything is exploiting the developers who explicitly stated that they want their code to stay open and developed in a certain way.&lt;/p&gt;
&lt;p&gt;Moreover, GitHub contains all sorts of code, from leaked source code to codebases with wildly incompatible licenses. Not all of these codebases can be used while developing your product.&lt;/p&gt;
&lt;p&gt;This is embrace, extend, extinguish at its finest, with a minefield attached to it.&lt;/p&gt;
&lt;p&gt;In the light of these events, I decided to stop using GitHub, and move to &lt;a href="https://sourcehut.org/"&gt;Source Hut&lt;/a&gt;. Source Hut is Drew DeVault's brainchild, a Free Software advocate. It's built with different priorities in mind, and without a social component deliberately. The software can be self-hosted if desired, however, I decided to pay for the service and support its development further.&lt;/p&gt;
&lt;p&gt;While I have started my move to Source Hut, there won't be much activity visible at first. My private research repositories (which will be eventually opened when they mature enough) are going first, then I'll archive my public archives and other public repositories, step by step.&lt;/p&gt;
&lt;p&gt;This slow migration will allow me to ponder on the plans for each project and make sure that I move them with utmost care and deliberation.&lt;/p&gt;
&lt;p&gt;Meanwhile, many people will inevitably wonder about their code's visibility and discoverability if they move from the most crowded open-source hub to somewhere relatively obscure and has no social components.&lt;/p&gt;
&lt;p&gt;I thought about this and decided that software freedom, ethics, self-respect, and doing the things you praise are much more important than being discoverable on a particular website. My &lt;a href="http://bayindirh.io"&gt;homepage&lt;/a&gt; has a link to my Source Hut page, and if people click that, it's great.&lt;/p&gt;
&lt;p&gt;Hope you at least take a look at &lt;a href="https://sr.ht"&gt;Source Hut&lt;/a&gt; or, other alternatives like &lt;a href="https://codeberg.org"&gt;Codeberg&lt;/a&gt; and &lt;a href="https://gitea.io/en-us/"&gt;Gitea&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope to see you over here.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Wed, 06 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/moving-to-source-hut/</guid></item><item><title>The Most Useful Statistical Test You Didn't Learn in School</title><link>https://specbranch.com/posts/kolmogorov-smirnov/</link><description>&lt;p&gt;In performance work, you will often find many distributions that are weirdly shaped: fat-tailed
distributions, distributions with a hard lower bound at a non-zero number, and distributions
that are just plain odd.  Particularly when you look at latency distributions, it is extremely
common for the 99th percentile to be a lot further from the mean than the 1st percentile.  These
sorts of asymmetric fat-tailed distributions come with the business.&lt;/p&gt;
&lt;p&gt;Often times, when performance engineers need to be scientific about their work, they will take
samples of these distributions, and put them into into a $t$-test to get a $p$-value for the
significance of their improvements.  That is what you learned in a basic statistics or lab science
class, so why not?  Unfortunately, the world of computers is more complicated than the beer
quality experiments for which the $t$-test was invented, and violates one of its core assumptions:
that the sample means are normally distributed.  When you have a lot of samples, this can hold,
but it often doesn't.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Mon, 04 Jul 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/kolmogorov-smirnov/</guid></item><item><title>We need to do a hard thing</title><link>https://mikewarot.blogspot.com/2022/07/we-need-to-do-hard-thing.html</link><description>&lt;p&gt;&amp;nbsp;We do need to do a hard thing, we need to reconfigure our world to cope with the end of the one time greatest economic bonanza of all times... the fossil fuel pulse.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If you think I'm about to go on about global warming/climate change/etc... NOPE&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We've tapped most of the easy to reach oil in the world. Now we're fracking to get at things, and those wells have decay rates of 40%/year, instead of per decade.&amp;nbsp; If we stopped all drilling, we'd have 40% less oil next year from all the new wells. (Or so I've been lead to believe. It's my opinion that we've got 20 years, at the outside to complete this project)&lt;br /&gt;&lt;br /&gt;The new shockingly high fuel costs? They're here to stay, no matter who "runs the country". They stopped building new refineries in the 1970s, because they knew this day was coming, and it didn't make sense to build more capacity for an industry they knew was heading to a peak. The only surprise was that some things broke faster than planned.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Our civilization depends on a resource in decline. All the people at the top have zero clue as to how to actively manage the situation. We, the people, have to start from the grass roots and figure this out ourselves.&lt;/p&gt;</description><author>--Mike--</author><pubDate>Sun, 03 Jul 2022 07:49:54 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/07/we-need-to-do-hard-thing.html</guid></item><item><title>Abortion isn't all about ending life - saying it is, is evil!</title><link>https://mikewarot.blogspot.com/2022/07/abortion-isnt-all-about-ending-life.html</link><description>&lt;div&gt;I've lost multiple nights of sleep, and simply have no coping skills because there exist in this world a large number of people who just love calling abortion "Baby Murder"&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These people obviously know the difference between a dead child lying on the ground in a classroom in Texas, and a few cells removed in the first half of a pregnancy... yet they persist in this evil game.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;If the upcoming laws in my Red State had been in effect 2 decades ago, I'd have no wife, she would have been killed, rather than have life saving procedure after we lost a more than welcome pregnancy. Thus she wouldn't have been with me to bring our lovely child into the world later.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;How many men will lose their wives, sisters, daughters... how many children will lose their mothers because of this evil befalling the land?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;How the f*ck can I get some sleep at night, knowing of all the evil indifference these people carry in their hearts?&lt;/div&gt;</description><author>--Mike--</author><pubDate>Fri, 01 Jul 2022 20:10:41 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/07/abortion-isnt-all-about-ending-life.html</guid></item><item><title>QDX Revision 3 Build Begins in REAL TIME</title><link>https://miscdotgeek.com/qdx-revision-3-build-begins-in-real-time/</link><description>&lt;p&gt;Hey everyone- been a busy few months lately. Between bad health, travelling, and then working hard just take care of Live Stuff, I&amp;#8217;ve hardly had time for the Ye Olde Blog! I&amp;#8217;ll try to write more regularly. A lot of my attention has been going to YouTube and in this series, starting with the video &amp;#8230; &lt;/p&gt;
&lt;p&gt;&lt;a class="more-link btn" href="https://miscdotgeek.com/qdx-revision-3-build-begins-in-real-time/" rel="noopener noreferrer" target="_self"&gt;Continue reading&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://miscdotgeek.com/qdx-revision-3-build-begins-in-real-time/" rel="noopener noreferrer" target="_self"&gt;QDX Revision 3 Build Begins in REAL TIME&lt;/a&gt; appeared first on &lt;a href="https://miscdotgeek.com" rel="noopener noreferrer" target="_self"&gt;MiscDotGeek&lt;/a&gt;.&lt;/p&gt;</description><author>MiscDotGeek</author><pubDate>Fri, 01 Jul 2022 05:16:16 GMT</pubDate><guid isPermaLink="true">https://miscdotgeek.com/qdx-revision-3-build-begins-in-real-time/</guid></item><item><title>CLI tip 12: squeeze empty lines</title><link>https://learnbyexample.github.io/tips/cli-tip-12/</link><description>&lt;p&gt;&lt;code&gt;awk&lt;/code&gt; has a builtin feature to process input content paragraph wise (by setting &lt;code&gt;RS&lt;/code&gt; to an empty string). But, did you know that &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;less&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt; can also be used to squeeze empty lines?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cat -s&lt;/code&gt; (and &lt;code&gt;less -s&lt;/code&gt;) will squeeze multiple empty lines in the input to a single empty line in the output. Here's an example:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat ip.txt
&lt;/span&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;world
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;banana
&lt;/span&gt;&lt;span&gt;cherry
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;tea coffee
&lt;/span&gt;&lt;span&gt;chocolate
&lt;/span&gt;&lt;span&gt;$ cat &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;s ip.txt
&lt;/span&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;world
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;banana
&lt;/span&gt;&lt;span&gt;cherry
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;tea coffee
&lt;/span&gt;&lt;span&gt;chocolate
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's an example with empty lines at the start/end of the input:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'\n\n\ndragon\n\n\nunicorn\n\n\n'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;dragon
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;unicorn
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'\n\n\ndragon\n\n\nunicorn\n\n\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; cat &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;s
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;dragon
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;unicorn
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's a solution with &lt;code&gt;awk&lt;/code&gt;. Unlike the &lt;code&gt;-s&lt;/code&gt; option, this will completely remove empty lines at the start/end of the input.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;RS&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'{print s $0; s=&amp;quot;\n&amp;quot;}'&lt;/span&gt;&lt;span&gt; ip.txt
&lt;/span&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;world
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;banana
&lt;/span&gt;&lt;span&gt;cherry
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;tea coffee
&lt;/span&gt;&lt;span&gt;chocolate
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'\n\n\ndragon\n\n\nunicorn\n\n\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; awk &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;RS&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'{print s $0; s=&amp;quot;\n&amp;quot;}'
&lt;/span&gt;&lt;span&gt;dragon
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;unicorn
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;awk&lt;/code&gt; solution would be easier to extend, given its programmable features. For example, two empty lines between the groups:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;RS&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'{print s $0; s=&amp;quot;\n\n&amp;quot;}'&lt;/span&gt;&lt;span&gt; ip.txt
&lt;/span&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;world
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;banana
&lt;/span&gt;&lt;span&gt;cherry
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;tea coffee
&lt;/span&gt;&lt;span&gt;chocolate
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's a surprising &lt;code&gt;GNU grep&lt;/code&gt; solution, with a customizable group separator:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# single empty line
&lt;/span&gt;&lt;span&gt;$ grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;--&lt;/span&gt;&lt;span&gt;group&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;separator= &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;A0 &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'.'&lt;/span&gt;&lt;span&gt; ip.txt
&lt;/span&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;world
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;banana
&lt;/span&gt;&lt;span&gt;cherry
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;tea coffee
&lt;/span&gt;&lt;span&gt;chocolate
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# double empty line
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# empty lines at the start/end of the input are removed too
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'\n\n\ndragon\n\n\nunicorn\n\n\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;--&lt;/span&gt;&lt;span&gt;group&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;separator=&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;$'&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span style="color: #d07711;"&gt;' -A0 '&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;dragon
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;unicorn
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/cli_text_processing_coreutils"&gt;CLI text processing with GNU Coreutils&lt;/a&gt;, &lt;a href="https://github.com/learnbyexample/learn_gnuawk"&gt;CLI text processing with GNU awk&lt;/a&gt; and &lt;a href="https://github.com/learnbyexample/learn_gnugrep_ripgrep"&gt;CLI text processing with GNU grep and ripgrep&lt;/a&gt; ebooks.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 29 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-12/</guid></item><item><title>2022–06–28: Pinephone Pro Type-C support is now complete</title><link>https://xnux.eu/log/#071</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 28 Jun 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#071</guid></item><item><title>Sharding Yourself</title><link>https://www.swyx.io/sharding-yourself</link><description>&lt;p&gt;An advanced tip for high-volume writers.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Mon, 27 Jun 2022 08:26:37 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/sharding-yourself</guid></item><item><title>Search index implementations</title><link>https://boyter.org/posts/search-index-implementations/</link><description>&lt;p&gt;A living document where I will be putting information about search index implementations as I learn about them.&lt;/p&gt;
&lt;p&gt;So there are a few talked about ways to search across content or build an index that I am aware of. Lets discuss each in term with its advantages and disadvantages&lt;/p&gt;
&lt;h3 id="brute-force"&gt;Brute Force&lt;/h3&gt;
&lt;p&gt;Brute Force, note that this isn&amp;rsquo;t an index strategy per say, but worth discussing anyway. Assuming you can get the entire corpus you are search into RAM it is possible to brute force search. I&amp;rsquo;m including it here so I have the advantages and disadvantages. While brute force isnt a solution to every problem, a lot of problems are pretty brute forcible given enough CPU and RAM.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Sun, 26 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/search-index-implementations/</guid></item><item><title>On The Importance of 15-5 Updates</title><link>https://www.swyx.io/the-importance-of-writing-weekly-updates</link><description>&lt;p&gt;We had a delightful discussion on the importance of writing weekly updates in this week's &lt;a href="https://learninpublic.org/#community"&gt;Coding Career Community meetup&lt;/a&gt;. I rarely get so excited about an idea I immediately know I need to start doing it, so I'm choosing to write it up to commit to it, and to share it with you.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sat, 25 Jun 2022 23:09:00 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/the-importance-of-writing-weekly-updates</guid></item><item><title>How to add a tachometer to a Triumph Street Twin (2016-2019)</title><link>http://blog.pythonaro.com/2022/06/how-to-add-tachometer-to-triumph-street.html</link><description>&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;I recently gave in to family tradition: I'm originally from Bologna, home of &lt;a href="https://www.ducati.com/" target="_blank"&gt;Ducati&lt;/a&gt; and heart of &lt;a href="https://www.bolognawelcome.com/en/blog/the-motor-valley" target="_blank"&gt;the Italian "Motor Valley"&lt;/a&gt;, so sooner or later I had to buy a motorbike (or two, but nevermind).&lt;/p&gt;
&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC3KW81DlbE6pbwtuDdllRiEv7JbtxyDCFeCuGrNaLrcSl1uuhK8fockkzhFkxNA5PuaSdG-CRqAPjv7DmZoJc1VzBZCyPgA9wJGLFiz0ZNQzNYgsT3H5t60RgP0WZYCvAUgye8l8t2HBejFKzv9Pf5OLGR214kiGzv9XMwbajK-NnO051vQ/s1556/IMG20220507121340.jpg" style="display: block; padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC3KW81DlbE6pbwtuDdllRiEv7JbtxyDCFeCuGrNaLrcSl1uuhK8fockkzhFkxNA5PuaSdG-CRqAPjv7DmZoJc1VzBZCyPgA9wJGLFiz0ZNQzNYgsT3H5t60RgP0WZYCvAUgye8l8t2HBejFKzv9Pf5OLGR214kiGzv9XMwbajK-NnO051vQ/s400/IMG20220507121340.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;As the main workhorse I went for a &lt;a href="https://www.motorcycle.com/specs/triumph/standard/2018/street-twin/base/detail.html" target="_blank"&gt;2018 Triumph Street Twin&lt;/a&gt;, because it's practical but still fun, fairly cheap, and simply beautiful. I love it to bits, but one thing I really missed: a tachometer ("rev counter"). While trying their hardest to segment the Bonneville range, Triumph clearly thought that people would pay a few grand more and get a Speed Twin just so that they could see RPMs. It took them about 4 years to understand the silliness of this position (or to produce enough Bonneville variations that nobody cares about that bit anymore), so post-2020 Street Twins display RPMs on the digital display - in a pretty small way, but at least it's there.&lt;/p&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;So, how could we go about adding a tachometer to pre-2020 models? Various web searches produced a few different methods, with a number of pitfalls. There are a few electrical schematics floating around, but I'm not good at that sort of thing and comments seemed to be that they are easy to get wrong.&lt;p&gt;

&lt;p&gt;A much easier method is to attach an OBDII ("OBD2") reader to the related port, which is available under the seat.&lt;/p&gt;
&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-pgOhrHFGfhReyY4tZmgOvvZeM202CU_NbTyf9TCycg4pdF6vnWZ9I7-xvTkyDsQggfAWK7j4pB9heFUfL4N5JnmsgHpoBj9pRNsRqBLlenGtxUnpHtPJkn3vGwQrfEeKsYYWIgk3ZnXBTPgZtqT_A-ekkVU9hvEud-Js7sW9r-GMRVfMQ/s1771/IMG20220622124158.jpg" style="display: block; padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-pgOhrHFGfhReyY4tZmgOvvZeM202CU_NbTyf9TCycg4pdF6vnWZ9I7-xvTkyDsQggfAWK7j4pB9heFUfL4N5JnmsgHpoBj9pRNsRqBLlenGtxUnpHtPJkn3vGwQrfEeKsYYWIgk3ZnXBTPgZtqT_A-ekkVU9hvEud-Js7sW9r-GMRVfMQ/s400/IMG20220622124158.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;OBDII is a standard interface for debugging systems in vehicles; it's recently been mandated by the European Union, so it's available in pretty much any vehicle produced in the last decade or so. Once you connect a reader, you can see a wealth of information about the vehicle, from fuel consumption to engine load to pretty much any sensor available... including RPMs! So that's how we can get a tachometer without effectively modifying anything in the bike itself.&lt;p&gt;

&lt;p&gt;There are two ways to show the extracted information: wired, and wireless. Each comes with pros and cons.&lt;/p&gt;

&lt;h3&gt;Wireless (Bluetooth)&lt;/h3&gt;
&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5fTo8JdHmSZ7KVt6YhOGix60G-SCwL2boEN-G2VeLY4FDOUc3HwI9sfJbmausnpipnxXvWel99UN18vBiqU_FyCtZcs1-IKmGJArWGwf3JbTBsec0Dbg5eThuvf5Uar7EfdhxusOPrHL0F_T-OFFTY6YRD2d7fMLV1IJhIlwdaojALDHoSA/s1319/IMG_20220623_093457.jpg" style="display: block; padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5fTo8JdHmSZ7KVt6YhOGix60G-SCwL2boEN-G2VeLY4FDOUc3HwI9sfJbmausnpipnxXvWel99UN18vBiqU_FyCtZcs1-IKmGJArWGwf3JbTBsec0Dbg5eThuvf5Uar7EfdhxusOPrHL0F_T-OFFTY6YRD2d7fMLV1IJhIlwdaojALDHoSA/s320/IMG_20220623_093457.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Wireless is less intrusive but fiddlier: a compact reader stays entirely under the seat, and communicates with a phone or tablet over Bluetooth (as far as I know, there are no dedicated wireless displays). It's described in &lt;a href="https://amzn.to/2CoSARQ" target="_blank"&gt;this Youtube video&lt;/a&gt;, and the dongles are &lt;a href="https://amzn.to/3zUxlFj" rel="sponsored" target="_blank"&gt;easy to find on Amazon&lt;/a&gt;. As a permanent solution, it suffers from lag and the requirement that the phone screen stays on all the time, set on the specific app. (Side note: I found the best iOS app to be &lt;a href="http://www.fourstroke.ca/" target="_blank"&gt;FourStroke&lt;/a&gt; - most of them are focused on cars and might not even work with cheap aftermarket readers.) I have an old phone I mount on handlebars, but I typically want to use it to display GPS stuff and play music, so that just didn't work for me. You also have to manually open the app and connect every time, after you start the bike, which is annoying.&lt;/p&gt;

&lt;h3&gt;Wired&lt;/h3&gt;
&lt;p&gt;A wired solution, on the other hand, requires a bit more setup, but you do it once and that's it, you don't have to worry about it ever again; readings are a bit less laggy (although still not as quick as hardware ones), and leave your phone free to do other stuff. They typically also feature hardware controls, which are easier to use with gloves than touchscreens (yes yes, I have modern gloves - in practice, they are still too big to be precise).&lt;/p&gt;

&lt;p&gt;There are a few OBDII readers on the market, largely meant for the car market. I grabbed &lt;a href="https://www.aliexpress.com/item/32886750530.html" target="_blank"&gt;this cheap thing from AliExpress&lt;/a&gt;, but there are &lt;a href="https://amzn.to/3NgV4Cm" rel="sponsored" target="_blank"&gt;equivalents on Amazon&lt;/a&gt; and so on. Setup is trivial: you connect it to the port, turn on the bike, and it just works, letting you choose what to display. You turn the bike off and the display shuts down automatically, so your battery is not drained. Nice!&lt;/p&gt;
  &lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-pgOhrHFGfhReyY4tZmgOvvZeM202CU_NbTyf9TCycg4pdF6vnWZ9I7-xvTkyDsQggfAWK7j4pB9heFUfL4N5JnmsgHpoBj9pRNsRqBLlenGtxUnpHtPJkn3vGwQrfEeKsYYWIgk3ZnXBTPgZtqT_A-ekkVU9hvEud-Js7sW9r-GMRVfMQ/s1771/IMG20220622124158.jpg" style="display: block; padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-pgOhrHFGfhReyY4tZmgOvvZeM202CU_NbTyf9TCycg4pdF6vnWZ9I7-xvTkyDsQggfAWK7j4pB9heFUfL4N5JnmsgHpoBj9pRNsRqBLlenGtxUnpHtPJkn3vGwQrfEeKsYYWIgk3ZnXBTPgZtqT_A-ekkVU9hvEud-Js7sW9r-GMRVfMQ/s400/IMG20220622124158.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
  
  &lt;p&gt;Finding a location for the wire is basically the same as for the USB you also find under the seat; if you've wired it up to a handlebar mount for phones, as I have, you can basically do the same - it's actually easier here, since you can push it further back with the other cables.&lt;/p&gt;
  &lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrvmjeQRKPM4cXzFqIM06XDE95AaOKdR0SRFW2FRTEkBt10IfNp5waTqTubmrg96TsxUmsepsnRpbsdiaDPqvUKLAIFmQ-7v3eXY2oApEtP2QjFHQsc060hMh4wCbpzNA6d9Iwh_bTo2Mfx77jWpmgkAYa-1aXEHu0V6Iu9Kdrl7RezaeV9g/s2070/IMG20220622124022.jpg" style="padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrvmjeQRKPM4cXzFqIM06XDE95AaOKdR0SRFW2FRTEkBt10IfNp5waTqTubmrg96TsxUmsepsnRpbsdiaDPqvUKLAIFmQ-7v3eXY2oApEtP2QjFHQsc060hMh4wCbpzNA6d9Iwh_bTo2Mfx77jWpmgkAYa-1aXEHu0V6Iu9Kdrl7RezaeV9g/s200/IMG20220622124022.jpg" width="200" /&gt;&lt;/a&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl3kBpOirJr2cCBAdpXVdu2FXx9ECPOiK7vEE7JdSlnB2cWX7Pz-66IDEuwrTCgncQLznqD1aVovtJhaTvS46jh6HVkw86lO5FBe-15yNnqZ0l_jUzt5f3XGj2BiAH59e21ckvBqIytsoYp1zPdCKCb99h9VEIWWDHTEca6edLpoeC8FVZwQ/s1757/IMG20220622123838.jpg" style="padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl3kBpOirJr2cCBAdpXVdu2FXx9ECPOiK7vEE7JdSlnB2cWX7Pz-66IDEuwrTCgncQLznqD1aVovtJhaTvS46jh6HVkw86lO5FBe-15yNnqZ0l_jUzt5f3XGj2BiAH59e21ckvBqIytsoYp1zPdCKCb99h9VEIWWDHTEca6edLpoeC8FVZwQ/s200/IMG20220622123838.jpg" width="200" /&gt;&lt;/a&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrLbkuzfUkVWeSvfpjt7gQocIctWaRFjGRd2BdjRylxorH-E3C6WI_EeuI6jthhOL92cZh8Pi4Wila4yQrv6Nw_ia2n08sPZ2SGrNdfEQ1PQ-021YLqkRqvFPHh05z-3ajS4DFOiMG1sf-JEnVGk-WEPPBcz4O9MgDiV7qPIvdTbvpTtvf-Q/s1942/IMG20220622123833.jpg" style="padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrLbkuzfUkVWeSvfpjt7gQocIctWaRFjGRd2BdjRylxorH-E3C6WI_EeuI6jthhOL92cZh8Pi4Wila4yQrv6Nw_ia2n08sPZ2SGrNdfEQ1PQ-021YLqkRqvFPHh05z-3ajS4DFOiMG1sf-JEnVGk-WEPPBcz4O9MgDiV7qPIvdTbvpTtvf-Q/s200/IMG20220622123833.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h4&gt;Unresolved issues&lt;/h4&gt;
&lt;p&gt;There are a few annoyances though, due to the fact that this is fundamentally a product for cars:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The display can be a bit hard to see in daylight, particularly when the sun shines directly on it.&lt;/li&gt;

&lt;li&gt;You'll need to hack together a mounting system; the stand that comes with the product is meant for car dashboards. You can see my solution in the pic of the display above - not the most beautiful, but it will do for now; I plan to revisit it at some point.&lt;/li&gt;

&lt;li&gt;It's not waterproof. In the rainy North of England, this is a significant problem. I'm trying to think about solutions; if you have any suggestion, feel free to drop a comment.&lt;/li&gt;
  &lt;/ul&gt;
&lt;p&gt;All these issues could be solved if manufacturers started making readers dedicated to the motorbike market. I hope that happens at some point, because it would be awesome - it would free consumers from the tiranny of OEM displays.&lt;/p&gt;

  &lt;h3&gt;Hot Engine is Hot&lt;/h3&gt;
  &lt;p&gt;
Last bit of advice: while you're testing, be careful with your dangling cables! As you can see from the pic below, I mistakenly left mine over the exhaust for a few seconds and... well. Amazingly, it still works!&lt;/p&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJjV_V5dAhpn5FCS_dPbQeoWX_ozansXl6QI_FWWKcLYPB91i4jFZdjBx0Wz2ZHY3Y6TmoR2UhaC4AU3KjabrlkZO8E3Tb5UyDzec3BP1C8tBuSMmdXWym0jmq_uwpV2v9QXgMoeLi6yAawkgQtqkUppVLCXhWV3yaGhN5bKbP3mO_d1vL0w/s1600/signal-2022-06-22-12-26-49-634-1.jpg" style="display: block; padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJjV_V5dAhpn5FCS_dPbQeoWX_ozansXl6QI_FWWKcLYPB91i4jFZdjBx0Wz2ZHY3Y6TmoR2UhaC4AU3KjabrlkZO8E3Tb5UyDzec3BP1C8tBuSMmdXWym0jmq_uwpV2v9QXgMoeLi6yAawkgQtqkUppVLCXhWV3yaGhN5bKbP3mO_d1vL0w/s400/signal-2022-06-22-12-26-49-634-1.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;</description><author>Subclassed</author><pubDate>Thu, 23 Jun 2022 11:48:10 GMT</pubDate><guid isPermaLink="true">http://blog.pythonaro.com/2022/06/how-to-add-tachometer-to-triumph-street.html</guid></item><item><title>Fun with Anchor Text Keywords</title><link>https://www.marginalia.nu/log/59-anchor-text/</link><description>&lt;p&gt;Anchor texts are a very useful source of keywords for a search engine, and in an older version of the search engine, it used the text of such hyperlinks as a supplemental source for keywords, but due to a few redesigns, this feature has fallen off.&lt;/p&gt;
&lt;p&gt;Last few days has been spent working on trying to re-implement it in a new and more powerful fashion. This has largely been enabled by a crawler re-design from a few months ago, which offers the crawled data in a lot more useful fashion and allows a lot more flexible post-processing.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Thu, 23 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/59-anchor-text/</guid></item><item><title>2022–06–23: Further Pinephone Pro camera development</title><link>https://xnux.eu/log/#070</link><author>megi's PinePhone Development Log</author><pubDate>Thu, 23 Jun 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#070</guid></item><item><title>Python tip 12: negate a regex grouping</title><link>https://learnbyexample.github.io/tips/python-tip-12/</link><description>&lt;p&gt;You might be familiar with negating a character class, for example:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; import &lt;/span&gt;&lt;span&gt;re
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# remove first two columns
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sub&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;\A&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;(&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;[&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;^&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;:]&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;+&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;:)&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;{2}&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'apple:42:banana:1000:cherry:512'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'banana:1000:cherry:512'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# filter all elements not ending with `r` or `t`
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;words &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'surrender'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'unicorn'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'newer'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'door'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'empty'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'eel'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'pest'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;[w &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for &lt;/span&gt;&lt;span&gt;w &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;words &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;if &lt;/span&gt;&lt;span&gt;re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;search&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;[&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;^&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;rt]&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;\Z&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, w)]
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'unicorn'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'empty'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'eel'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But do you know how to match characters based on a negated group? You can use a combination of negative lookahead and quantifiers as shown in the examples below:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;pets &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'fox,cat,dog,parrot'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# match if 'do' is not present between 'at' and 'par'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;bool&lt;/span&gt;&lt;span&gt;(re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;search&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;at((&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;?!&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;do)&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;.&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;)&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;par&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, pets))
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;False
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# match if 'go' is not present between 'at' and 'par'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;bool&lt;/span&gt;&lt;span&gt;(re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;search&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;at((&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;?!&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;go)&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;.&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;)&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;par&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, pets))
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# easier to understand by looking at the matched portions
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;search&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;at((&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;?!&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;go)&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;.&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;)&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;par&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, pets)[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'at,dog,par'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;search&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;\A&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;((&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;?!&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;par)&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;.&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;)&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, pets)[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'fox,cat,dog,'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.&lt;/code&gt; in &lt;code&gt;((?!go).)*&lt;/code&gt; will match a character only if the sequence of current and next characters are not &lt;code&gt;go&lt;/code&gt;. Similarly, the &lt;code&gt;.&lt;/code&gt; in &lt;code&gt;((?!par).)*&lt;/code&gt; matches a character only if the current and next two characters are not &lt;code&gt;par&lt;/code&gt;. The &lt;code&gt;*&lt;/code&gt; quantifier is applied on the outer group to match zero or more characters satisfying the given condition.&lt;/p&gt;
&lt;p&gt;The outer group in the above examples are capturing groups, though it wasn't required. Just makes the pattern concise. However, capturing groups affect the behavior of functions like &lt;code&gt;re.split&lt;/code&gt; and &lt;code&gt;re.findall&lt;/code&gt;. You can use non-capturing groups in such cases:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #7f8989;"&gt;# capture group affects the behavior of 're.findall'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;findall&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;\b&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;((&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;?!&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;42)&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\w&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;)&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;+\b&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a422b good bad42 nice100'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'d'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'0'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# so, use a non-capturing group here
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;findall&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;\b&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;(?:(&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;?!&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;42)&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\w&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;)&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;+\b&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a422b good bad42 nice100'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'good'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'nice100'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Test your understanding by solving this exercise. Construct a regex solution that works for all three sample transformations shown below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Power(x,2)&lt;/code&gt; should be replaced with &lt;code&gt;(x)*(x)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Power(Power(x,2) + x,2)&lt;/code&gt; should be changed to &lt;code&gt;((x)*(x) + x)*((x)*(x) + x)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Power(x + Power(x,2),2)&lt;/code&gt; should be changed to &lt;code&gt;(x + (x)*(x))*(x + (x)*(x))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If that was easy, make it work for general powers instead of just &lt;code&gt;2&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Power(Power(x,2),3)&lt;/code&gt; translates to &lt;code&gt;((x)*(x))*((x)*(x))*((x)*(x))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The above exercise is based on &lt;a href="https://stackoverflow.com/q/67214116/4082052"&gt;this stackoverflow Q&amp;amp;A&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/py_regular_expressions"&gt;Understanding Python re(gex)?&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 22 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-12/</guid></item><item><title>CLI tip 7: limiting number of filtered lines</title><link>https://learnbyexample.github.io/tips/cli-tip-7/</link><description>&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; supports &lt;code&gt;-m&lt;/code&gt; option to specify the maximum number of matching lines in the output.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# all input lines containing 'a'
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a'
&lt;/span&gt;&lt;span&gt;goal
&lt;/span&gt;&lt;span&gt;rate
&lt;/span&gt;&lt;span&gt;eat
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# maximum of 2 matching lines
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m2 &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a'
&lt;/span&gt;&lt;span&gt;goal
&lt;/span&gt;&lt;span&gt;rate
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m2 &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'pi'
&lt;/span&gt;&lt;span&gt;pit
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# example with -v option
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'e'
&lt;/span&gt;&lt;span&gt;goal
&lt;/span&gt;&lt;span&gt;pit
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m1 &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'e'
&lt;/span&gt;&lt;span&gt;goal
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With multiple file input, the restriction is applied for each file &lt;em&gt;separately&lt;/em&gt;.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat table.txt 
&lt;/span&gt;&lt;span&gt;brown bread mat cake &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42
&lt;/span&gt;&lt;span&gt;blue cake mug shirt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;span&gt;yellow banana window shoes &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3.14
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; ip.txt
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m1 &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'i'&lt;/span&gt;&lt;span&gt; table.txt ip.txt
&lt;/span&gt;&lt;span&gt;table.txt&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span&gt;blue cake mug shirt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;span&gt;ip.txt&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span&gt;pit
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# use 'cat' if you want to operate on combined input
&lt;/span&gt;&lt;span&gt;$ cat table.txt ip.txt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m1 &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'i'
&lt;/span&gt;&lt;span&gt;blue cake mug shirt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;span&gt;$ cat table.txt ip.txt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;m1 &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'go'
&lt;/span&gt;&lt;span&gt;goal
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/learn_gnugrep_ripgrep"&gt;CLI text processing with GNU grep and ripgrep&lt;/a&gt; ebook if you are interested in learning about &lt;code&gt;GNU grep&lt;/code&gt; and &lt;code&gt;ripgrep&lt;/code&gt; commands in more detail.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Mon, 20 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-7/</guid></item><item><title>Python tip 7: creating a deepcopy of collections</title><link>https://learnbyexample.github.io/tips/python-tip-7/</link><description>&lt;p&gt;From &lt;a href="https://docs.python.org/3/library/copy.html#module-copy"&gt;copy&lt;/a&gt; built-in module:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The shared binding is helpful for cases like in-place modification of lists within a user defined function:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="background-color: #562d56bf; color: #f8f8f8;"&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;rotate&lt;/span&gt;&lt;span&gt;(ip):
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span&gt;ip.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;, ip.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;pop&lt;/span&gt;&lt;span&gt;())
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;321&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5.3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;rotate&lt;/span&gt;&lt;span&gt;(nums)
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;321&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5.3&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use the &lt;code&gt;copy.deepcopy()&lt;/code&gt; method if you wish to recursively create new copies of all the elements of a mutable object:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; import &lt;/span&gt;&lt;span&gt;copy
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums_2d &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10&lt;/span&gt;&lt;span&gt;], [&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0.2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;], [&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;200&lt;/span&gt;&lt;span&gt;]]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums_2d_deepcopy &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;copy.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;deepcopy&lt;/span&gt;&lt;span&gt;(nums_2d)
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums_2d_deepcopy[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;][&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'yay'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums_2d_deepcopy
&lt;/span&gt;&lt;span&gt;[[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'yay'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10&lt;/span&gt;&lt;span&gt;], [&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0.2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;], [&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;200&lt;/span&gt;&lt;span&gt;]]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums_2d
&lt;/span&gt;&lt;span&gt;[[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10&lt;/span&gt;&lt;span&gt;], [&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0.2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;], [&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;200&lt;/span&gt;&lt;span&gt;]]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://learnbyexample.github.io/100_page_python_intro/mutability.html"&gt;Mutability&lt;/a&gt; chapter from my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook for more details on this topic.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Mon, 20 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-7/</guid></item><item><title>Data outlasts Code, yet Code keeps winning</title><link>https://www.swyx.io/data-outlasts-code-but</link><description>&lt;p&gt;My recent &lt;a href="https://dx.tips/the-end-of-localhost"&gt;End of Localhost&lt;/a&gt; piece on &lt;a href="https://news.ycombinator.com/item?id=31669762"&gt;Hacker News&lt;/a&gt; came with the usual dash of HN criticism devolving into &lt;a href="https://news.ycombinator.com/item?id=31669762#31671401"&gt;blaming beginners for not knowing the same parts of the stack that they consider mandatory&lt;/a&gt;:&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sat, 18 Jun 2022 21:56:56 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/data-outlasts-code-but</guid></item><item><title>Culture Docs: Facebook, Netflix and Valve</title><link>https://bytepawn.com/culture-docs-facebook-netflix-and-valve.html</link><description>&lt;p&gt;Many companies have some sort of "Culture Doc", a booklet or similar, which explains to new joiners what the company is about. I received Facebook's "Little Red Booklet" when I joined in 2016 February, and I was amazed how good it was. Recently I was researching other companies' Culture Docs, and found a version of Netflix's and Valve's online. It's interesting to compare and contrast what these different companies choose to put in their Culture Doc. Facebook's Culture Doc is very mission and execution oriented and serious, Netflix is analytical and HR-focused, and Valve's is a lighthearted explanation of how the company works.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Move fast and break things" src="https://v1.benbarry.com/images/portfolio/600/benbarry-000152.jpg" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 18 Jun 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/culture-docs-facebook-netflix-and-valve.html</guid></item><item><title>CLI tip 6: filtering lines based on multiple conditions</title><link>https://learnbyexample.github.io/tips/cli-tip-6/</link><description>&lt;p&gt;Usually, &lt;code&gt;grep&lt;/code&gt; is used for filtering lines based on a regexp pattern. Matching multiple patterns as a conditional OR is easy to apply using alternation. For example, &lt;code&gt;grep -E 'bread|banana'&lt;/code&gt; matches lines containing either &lt;code&gt;bread&lt;/code&gt; or &lt;code&gt;banana&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, conditional AND requires multiple &lt;code&gt;grep&lt;/code&gt; commands or the use of lookarounds if PCRE feature is available. A simpler alternative is to use &lt;code&gt;awk&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat table.txt
&lt;/span&gt;&lt;span&gt;brown bread mat cake &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42
&lt;/span&gt;&lt;span&gt;blue cake mug shirt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;span&gt;yellow banana window shoes &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3.14
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# line containing 'cake' but not 'at'
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# same as: grep 'cake' table.txt | grep -v 'at'
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# with PCRE: grep -P '^(?!.*at).*cake' table.txt
&lt;/span&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'/cake/ &amp;amp;&amp;amp; !/at/'&lt;/span&gt;&lt;span&gt; table.txt
&lt;/span&gt;&lt;span&gt;blue cake mug shirt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# first field containing 'low' or the last field is less than 0
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# not easy to construct a grep solution here due to field/numeric comparison
&lt;/span&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'$1 ~ /low/ || $NF&amp;lt;0'&lt;/span&gt;&lt;span&gt; table.txt
&lt;/span&gt;&lt;span&gt;blue cake mug shirt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;span&gt;yellow banana window shoes &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3.14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/learn_gnuawk"&gt;CLI text processing with GNU awk&lt;/a&gt; ebook if you are interested in learning about the &lt;code&gt;awk&lt;/code&gt; command in more detail.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 17 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-6/</guid></item><item><title>Python tip 6: inplace file editing</title><link>https://learnbyexample.github.io/tips/python-tip-6/</link><description>&lt;p&gt;The built-in &lt;a href="https://docs.python.org/3/library/fileinput.html"&gt;fileinput module&lt;/a&gt; has nice features for file processing, especially handy for multiple files and inplace editing. Here's an example:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #7f8989;"&gt;# inplace.py
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;import &lt;/span&gt;&lt;span&gt;fileinput
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;with &lt;/span&gt;&lt;span&gt;fileinput.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;input&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;inplace&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;as &lt;/span&gt;&lt;span&gt;f:
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for &lt;/span&gt;&lt;span&gt;line &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;f:
&lt;/span&gt;&lt;span&gt;        &lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# do some processing
&lt;/span&gt;&lt;span&gt;        op &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;line.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'search'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'replace'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;        &lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# print() the text you want to write back to the input files
&lt;/span&gt;&lt;span&gt;        &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(op, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;end&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, files passed as CLI arguments will be processed:&lt;/p&gt;
&lt;pre class="language-bash " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-bash"&gt;&lt;span style="color: #5597d6;"&gt;$&lt;/span&gt;&lt;span&gt; python3 inplace.py &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;.md
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; If you already know which inputs have to be processed, use the &lt;code&gt;files&lt;/code&gt; argument. Use the &lt;code&gt;backup&lt;/code&gt; argument if you want to make copies of original files in case something goes wrong. See my blog post &lt;a href="https://www.python-engineer.com/posts/inplace-file-editing/"&gt;In-place file editing with fileinput module&lt;/a&gt; for more details and examples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook for a short, introductory guide for the Python programming language.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 17 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-6/</guid></item><item><title>CLI tip 5: aligning columns</title><link>https://learnbyexample.github.io/tips/cli-tip-5/</link><description>&lt;p&gt;The &lt;code&gt;column&lt;/code&gt; command is a nifty tool to align input data column wise. By default, whitespace is used as the input delimiter. Space character is used to align the output columns, so whitespace characters like tab will get converted to spaces.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'one two three\nfour five six\n'
&lt;/span&gt;&lt;span&gt;one two three
&lt;/span&gt;&lt;span&gt;four five six
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'one two three\nfour five six\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; column &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;t
&lt;/span&gt;&lt;span&gt;one   two   three
&lt;/span&gt;&lt;span&gt;four  five  six
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use the &lt;code&gt;-s&lt;/code&gt; option to customize the input delimiter. Note that the output delimiter will still be made up of spaces only.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat scores.csv
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Maths&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Physics&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Chemistry
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Ith&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Cy&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;97&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;98&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;95
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Lin&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;83&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;80
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ column &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;s, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;t scores.csv
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Name  Maths  Physics  Chemistry
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Ith   &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100    100      100
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Cy    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;97     98       95
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Lin   &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78     83       80
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'1:-:2:-:3\napple:-:banana:-:cherry\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; column &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;s:&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-: -&lt;/span&gt;&lt;span&gt;t
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1      2       3
&lt;/span&gt;&lt;span&gt;apple  banana  cherry
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="warning" src="/images/warning.svg" /&gt; Input should have a newline at the end, otherwise you'll get an error:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'1 2 3\na   b   c' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; column &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;t
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;column:&lt;/span&gt;&lt;span&gt; line too long
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1  2  3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/cli-computing"&gt;Linux Command Line Computing&lt;/a&gt; ebook and &lt;code&gt;man column&lt;/code&gt; for more details.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 17 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-5/</guid></item><item><title>On automation</title><link>https://blog.bayindirh.io/blog/on-automation/</link><description>&lt;p&gt;Exploring minimalism is a multifaceted journey. As I travel down the path; different ideas, problems, ways and possibilities appear. These branches lead to different interpretations of minimalism, but some of them brings the ultimate vision of more time and inner peace nearer. One of such paths is workflows.&lt;/p&gt;
&lt;p&gt;Every human being performs repetitive tasks. The tasks are small in size, relatively easy and doesn't require much brain power, hence we don't think about them. However, they require time, as every task. Moreover, they like to appear in inconvenient times or pile up when we decide to skip them a couple of times, and this adds to the background stress of our lives.&lt;/p&gt;
&lt;p&gt;These factors create incentives to reduce the background stress the task at hand creates, and there are possible ways to tackle this problem. If possible, we can eliminate it. If not, we can transfer the task to someone, and that someone doesn't have to be another human.&lt;/p&gt;
&lt;p&gt;Enter automation.&lt;/p&gt;
&lt;p&gt;Automation has similar promises with &lt;a href="https://blog.bayindirh.io/blog/meditations-on-minimalism/"&gt;minimalism&lt;/a&gt;. Less mental load and more time. By creating workflows which can handle all the steps needed to accomplish a task, a 5-minute task can become a 5-second one. While this is a nice and enticing promise, it sounds too good to be true.&lt;/p&gt;
&lt;p&gt;Because it is.&lt;/p&gt;
&lt;p&gt;Many tasks we do intuitively can't be understood by computers well. This is why we have artificial intelligence and machine learning, but there are tasks we can automate. This automation can be done with dedicated tools or we can write ours, and program our woes away we think. However, wise men have threaded this path before and left us clues.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The first 90 percent of the code accounts for the first 90 percent of the development time. The remaining 10 percent of the code accounts for the other 90 percent of the development time.&lt;br /&gt;
-- Tom Cargill, Bell Labs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There's another, visual explanation by venerable Randall Munroe of XKCD.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Automation" src="https://bayindirh.mataroa.blog/images/e0459599.png" /&gt;&lt;/p&gt;
&lt;p&gt;In reality, the path which looked exciting at first becomes thorny as we start to explore the depths, hence we have to thread carefully, and be aware of the traps ahead.&lt;/p&gt;
&lt;p&gt;However, there's no need to abandon all hope.&lt;/p&gt;
&lt;p&gt;With little preparation, and by being mindful of what we are trying to accomplish, we can navigate this maze and create tools which can take the loads from our shoulders and bear it without any complaints. The key is remembering two things: keeping it simple and iterating.&lt;/p&gt;
&lt;p&gt;The first thing is more important one of the bunch, because as a passionate developer, I tend to over engineer. I need to avoid that, hence I plan for the minimum feature set which the tool needs to get the job done. The second one allows me to improve the tool, without crippling my life and the workflow. These iterations add emerging requirements or the features I thought it'd be useful (hint: I abandon at least half of these ideas since they bring no benefit).&lt;/p&gt;
&lt;p&gt;When a tool deploys to production and starts to do its job, the mental space it creates is priceless. Because a job always takes more time than it looks. You mentally prepare for it, think about it until the right time comes and then perform. Offloading this to an impeccable agent is a nice thing.&lt;/p&gt;
&lt;p&gt;Lastly, watching the machinery I built run makes me happy and creates a satisfaction which I can't describe.&lt;/p&gt;
&lt;p&gt;One such tool I created is &lt;a href="https://github.com/hbayindir/magazine-renamer"&gt;Magazine Renamer&lt;/a&gt;, which allows me to organize my IEEE magazines when they arrive to my inbox. Another, a more ambitious tool is in the works, but it'll take some time to get ready. Will share that one too, but it needs to be useable first.&lt;/p&gt;
&lt;p&gt;I think everyone should automate some parts of their life without getting overzealous about it, because sometimes doing things manually are better, however discussion of this a matter of another time.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Thu, 16 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/on-automation/</guid></item><item><title>The 8 Jobs of Management</title><link>https://www.swyx.io/the-8-jobs-of-management</link><description>&lt;p&gt;Recently, John Cutler &lt;a href="https://twitter.com/johncutlefish/status/1533661807029563392?s=21&amp;#x26;t=WJORvdw2EyoLB1ChjQ8NpA"&gt;tweeted&lt;/a&gt; a chart on the view of management:&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Wed, 15 Jun 2022 23:12:25 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/the-8-jobs-of-management</guid></item><item><title>Vim tip 10: Undo and Redo</title><link>https://learnbyexample.github.io/tips/vim-tip-10/</link><description>&lt;p&gt;In Normal mode, you can undo and redo changes using the following commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;u&lt;/kbd&gt; undo last change
&lt;ul&gt;
&lt;li&gt;press &lt;kbd&gt;u&lt;/kbd&gt; again for further undos&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;U&lt;/kbd&gt; undo latest changes on last edited line&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;r&lt;/kbd&gt; redo a change undone by &lt;kbd&gt;u&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;U&lt;/kbd&gt; redo changes undone by &lt;kbd&gt;U&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/usr_32.txt.html#32.3"&gt;:h 32.3&lt;/a&gt; for details on &lt;kbd&gt;g-&lt;/kbd&gt; and &lt;kbd&gt;g+&lt;/kbd&gt; commands that you can use to undo branches.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 15 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-10/</guid></item><item><title>Python tip 5: random choice and sample</title><link>https://learnbyexample.github.io/tips/python-tip-5/</link><description>&lt;p&gt;Here are a couple of commonly used methods for the built-in &lt;code&gt;random&lt;/code&gt; module:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;choice()&lt;/code&gt; method helps you get a random element&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sample()&lt;/code&gt; method helps you get a &lt;code&gt;list&lt;/code&gt; of a specific count of random elements&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; import &lt;/span&gt;&lt;span&gt;random
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;51&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;22&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;random.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;choice&lt;/span&gt;&lt;span&gt;(nums)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;random.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sample&lt;/span&gt;&lt;span&gt;(nums, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;k&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;51&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;random.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;sample&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b39f04;"&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1000&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;k&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;490&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;26&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;9&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;745&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;919&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Both these methods will work on any sequence object. The &lt;code&gt;sample()&lt;/code&gt; method also accepts a &lt;code&gt;set&lt;/code&gt; object, but that will be deprecated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook for a short, introductory guide for the Python programming language.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 14 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-5/</guid></item><item><title>CLI tip 4: serialize file contents to a single line</title><link>https://learnbyexample.github.io/tips/cli-tip-4/</link><description>&lt;p&gt;The &lt;code&gt;-s&lt;/code&gt; option is one of the useful, but lesser known feature of the &lt;code&gt;paste&lt;/code&gt; command. It helps you to serialize input file contents to a single output line.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat colors.txt
&lt;/span&gt;&lt;span&gt;blue
&lt;/span&gt;&lt;span&gt;white
&lt;/span&gt;&lt;span&gt;orange
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ paste &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;sd, colors.txt
&lt;/span&gt;&lt;span&gt;blue,white,orange
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If multiple files are passed, serialization of each file is displayed on separate output lines.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ paste &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;sd: &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;(seq &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;(seq &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5 9&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;8&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The advantage of using &lt;code&gt;paste&lt;/code&gt; instead of other options like &lt;code&gt;tr&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, etc is that you do not have to worry about trailing delimiters, newlines, etc. For example:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# issue 1: trailing comma
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# issue 2: no newline at the end
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;colors.txt tr &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'\n' ','
&lt;/span&gt;&lt;span&gt;blue,white,orange,
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# correcting the above two issues
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;colors.txt tr &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'\n' ',' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; sed &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'s/,$/\n/'
&lt;/span&gt;&lt;span&gt;blue,white,orange
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's an equivalent &lt;code&gt;awk&lt;/code&gt; solution for single file input. While slower and complicated compared to the &lt;code&gt;paste&lt;/code&gt; solution, you get more flexibility since &lt;code&gt;awk&lt;/code&gt; is a programming language. For example, it is pretty easy to use multicharacter output delimiter.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;ORS&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'NR&amp;gt;1{print &amp;quot;,&amp;quot;} 1; END{print &amp;quot;\n&amp;quot;}'&lt;/span&gt;&lt;span&gt; colors.txt
&lt;/span&gt;&lt;span&gt;blue,white,orange
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;ORS&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'NR&amp;gt;1{print &amp;quot; : &amp;quot;} 1; END{print &amp;quot;\n&amp;quot;}'&lt;/span&gt;&lt;span&gt; colors.txt
&lt;/span&gt;&lt;span&gt;blue &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span&gt; white &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span&gt; orange
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://learnbyexample.github.io/cli_text_processing_coreutils/paste.html"&gt;paste command&lt;/a&gt; chapter from my &lt;a href="https://github.com/learnbyexample/cli_text_processing_coreutils"&gt;Command line text processing with GNU Coreutils&lt;/a&gt; ebook for more details.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/learn_gnuawk"&gt;CLI text processing with GNU awk&lt;/a&gt; ebook if you are interested in learning about the &lt;code&gt;awk&lt;/code&gt; command.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 14 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-4/</guid></item><item><title>CLI tip 3: place backups in another directory with GNU sed</title><link>https://learnbyexample.github.io/tips/cli-tip-3/</link><description>&lt;p&gt;You can use &lt;code&gt;*&lt;/code&gt; to place backups of original files in another directory when using the &lt;code&gt;-i&lt;/code&gt; option with &lt;code&gt;GNU sed&lt;/code&gt;. Consider these two sample input files in the current directory:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat f1.txt
&lt;/span&gt;&lt;span&gt;good morning
&lt;/span&gt;&lt;span&gt;that was good, just too good!
&lt;/span&gt;&lt;span&gt;$ cat f2.txt 
&lt;/span&gt;&lt;span&gt;goodie goodbye
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a &lt;code&gt;backups&lt;/code&gt; directory and use &lt;code&gt;*&lt;/code&gt; under this directory as a placeholder for the filenames passed to the &lt;code&gt;sed&lt;/code&gt; command.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ mkdir backups
&lt;/span&gt;&lt;span&gt;$ sed &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'backups/*' 's/good/nice/'&lt;/span&gt;&lt;span&gt; f1.txt f2.txt
&lt;/span&gt;&lt;span&gt;$ ls backups&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/
&lt;/span&gt;&lt;span&gt;f1.txt  f2.txt
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# modified content
&lt;/span&gt;&lt;span&gt;$ cat f1.txt
&lt;/span&gt;&lt;span&gt;nice morning
&lt;/span&gt;&lt;span&gt;that was nice, just too good!
&lt;/span&gt;&lt;span&gt;$ cat f2.txt
&lt;/span&gt;&lt;span&gt;niceie goodbye
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# backed-up original content
&lt;/span&gt;&lt;span&gt;$ cat backups&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span&gt;f1.txt 
&lt;/span&gt;&lt;span&gt;good morning
&lt;/span&gt;&lt;span&gt;that was good, just too good!
&lt;/span&gt;&lt;span&gt;$ cat backups&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span&gt;f2.txt
&lt;/span&gt;&lt;span&gt;goodie goodbye
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since &lt;code&gt;*&lt;/code&gt; expands to the name of the input files, you can also use this feature when you need to add a prefix for the backups.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ sed &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bkp.*' 's/green/yellow/'&lt;/span&gt;&lt;span&gt; colors.txt
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ ls &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;colors&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*
&lt;/span&gt;&lt;span&gt;bkp.colors.txt  colors.txt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; The &lt;code&gt;*&lt;/code&gt; trick works with Perl as well, see &lt;a href="https://learnbyexample.github.io/learn_perl_oneliners/in-place-file-editing.html"&gt;In-place file editing&lt;/a&gt; chapter from my &lt;a href="https://github.com/learnbyexample/learn_perl_oneliners"&gt;Perl One-Liners Guide&lt;/a&gt; ebook for examples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/learn_gnused"&gt;CLI text processing with GNU sed&lt;/a&gt; ebook if you are interested in learning about the &lt;code&gt;GNU sed&lt;/code&gt; command in more detail.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 14 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-3/</guid></item><item><title>Beginner Harmonica Practice Exercises</title><link>https://smcleod.net/2022/06/beginner-harmonica-practice-exercises/</link><description>&lt;h1 id="beginner-harmonica-practice-exercises"&gt;Beginner Harmonica Practice Exercises&lt;/h1&gt;
&lt;p&gt;Way back in around 2008 I wrote up a doc with a list of beginner harp exercises and practice riffs, at the time it was uploaded to a few forums and a shared Google doc - both have since disappeared. To this day I still get regular emails asking for a copy of it so I thought I&amp;rsquo;d copy it to a post here.&lt;/p&gt;
&lt;p&gt;Note: I haven&amp;rsquo;t updated these since around 2011.&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Mon, 13 Jun 2022 16:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/06/beginner-harmonica-practice-exercises/</guid></item><item><title>A chance to act, let's close the Boyfriend Loophole - the right way!</title><link>https://mikewarot.blogspot.com/2022/06/a-chance-to-act-lets-close-boyfriend.html</link><description>&lt;p&gt;&amp;nbsp;Closing the "Boyfriend Loophole" could do a great deal to stop future mass shootings. Someone who can't handle their feelings around people close to them enough to avoid violence, shouldn't be allowed to own firearms.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This is THE BEST CHANCE we have at the moment, likely in the next year or two, for actually fixing some of the biggest problems facing our nation. The huge overlap between those who commit domestic violence, and mass shooters, is well proven.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I hope that we can push our representatives to do the right thing on this. Pretty much EVERYONE agrees that this legislation is needed, let's not let them f*ck it up.&lt;/p&gt;&lt;div&gt;Here's Beau explaining why the details matter.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;</description><author>--Mike--</author><pubDate>Mon, 13 Jun 2022 04:31:53 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/06/a-chance-to-act-lets-close-boyfriend.html</guid></item><item><title>The Hard Problem of Rendering Tweets</title><link>https://www.swyx.io/the-hard-problem-of-rendering-tweets</link><description>&lt;p&gt;I've been unhappy with my &lt;a href="https://github.com/sw-yx/swyxkit/issues/61"&gt;tweet rendering strategy&lt;/a&gt; for a while - Twitter encourages you to use their heavy JS script to render tweets, which undoubtedly heaps all sorts of tracking on the reader, docks your lighthouse performance score by ~17 points, adds ~4 seconds to Time to Interactive, occasionally gets adblocked (so &lt;em&gt;nothing&lt;/em&gt; renders!)&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sun, 12 Jun 2022 20:47:39 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/the-hard-problem-of-rendering-tweets</guid></item><item><title>Python tip 4: comparison chaining</title><link>https://learnbyexample.github.io/tips/python-tip-4/</link><description>&lt;p&gt;You can chain comparison operators arbitrarily. Apart from terser code, this also has the advantage of having to evaluate the middle expression only once.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; from &lt;/span&gt;&lt;span&gt;math &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;import &lt;/span&gt;&lt;span&gt;factorial
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# factorial function gets called twice for this example
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;factorial&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;and &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;factorial&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# function needs to be called only once here
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;factorial&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# another example
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bat' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cat' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cater'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook for a short, introductory guide for the Python programming language.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 10 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-4/</guid></item><item><title>One year as a solo dev building open-source data tools without funding</title><link>http://notes.eatonphil.com/2022-06-11-year-in-review.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-06-11-year-in-review.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Fri, 10 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/2022-06-11-year-in-review.html</guid></item><item><title>The End of Localhost</title><link>https://www.swyx.io/the-end-of-localhost</link><description>&lt;blockquote&gt;
&lt;p&gt;This post was originally published on my new dedicated DX site: https://dx.tips/the-end-of-localhost&lt;/p&gt;
&lt;/blockquote&gt;</description><author>swyx's site RSS Feed</author><pubDate>Wed, 08 Jun 2022 20:26:56 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/the-end-of-localhost</guid></item><item><title>CLI tip 11: longest line length</title><link>https://learnbyexample.github.io/tips/cli-tip-11/</link><description>&lt;p&gt;You can use &lt;code&gt;wc -L&lt;/code&gt; to report the length of the longest line in the input (excluding the newline character of a line).&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'apple' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# last line not ending with newline won't be a problem
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'apple\nbanana' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ cat greeting.txt
&lt;/span&gt;&lt;span&gt;hi there
&lt;/span&gt;&lt;span&gt;have a nice day
&lt;/span&gt;&lt;span&gt;$ wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;greeting.txt
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If multiple files are passed, the last line summary will show the maximum length among the given inputs.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L&lt;/span&gt;&lt;span&gt; greeting.txt sample.txt para.txt
&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;15&lt;/span&gt;&lt;span&gt; greeting.txt
&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;26&lt;/span&gt;&lt;span&gt; sample.txt
&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;11&lt;/span&gt;&lt;span&gt; para.txt
&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;26&lt;/span&gt;&lt;span&gt; total
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-L&lt;/code&gt; won't count non-printable characters and tabs are converted to equivalent spaces. You can use &lt;code&gt;awk&lt;/code&gt; if these are not acceptable.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# tab characters can occupy up to 8 columns
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'\t' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;8
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'(\t)' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;9
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'(\t)' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'{print length()}'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# non-printable characters aren't counted
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'(\34)' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'(\34)' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'{print length()}'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the &lt;code&gt;awk&lt;/code&gt; command in the above illustration is similar to &lt;code&gt;wc -L&lt;/code&gt; only for single line inputs. For multiple lines, you can use the following command:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;awk &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'{len = length(); if(len &amp;gt; max) max = len} END{print max}'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Multibyte characters and &lt;a href="https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries"&gt;grapheme clusters&lt;/a&gt; will each be counted as &lt;code&gt;1&lt;/code&gt;, assuming the current locale is set appropriately:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# multibyte characters are counted as 1 each in supported locales
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'αλεπού' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# grapheme cluster example
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cag̈e' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# non-supported locales can cause them to be treated as non-printable
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'αλεπού' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;| &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;LC_ALL&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;C&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;L
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/cli_text_processing_coreutils"&gt;Command line text processing with GNU Coreutils&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 08 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-11/</guid></item><item><title>Iron Arachne Dungeon Generator and future plans</title><link>https://benovermyer.com/blog/2022/06/iron-arachne-dungeon-generator/</link><description>&lt;p&gt;This weekend past, I launched the dungeon generator for Iron Arachne. I've been working on it off and on
for a few weeks and I finally got it to the point where it was usable and useful. However, it's by no means
complete, and a lot of features were left unfinished.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/06/iron-arachne-dungeon-generator/dungeon-map-01.png" /&gt;
&lt;p&gt;The above is an example of the maps it currently generates. In terms of pathing, there is a pretty linear
flow to the dungeon layout - a higher-number room is deeper into the dungeon. This makes it easy to determine
where to put goals like boss encounters. However, it also means the dungeon doesn't encourage exploration
or reward players who enjoy that activity, and really it gets a little boring.&lt;/p&gt;
&lt;p&gt;So, one of the first changes is going to be the addition of more loops throughout the layout. This will
result in more connections between rooms. Corridors will need to be addressed. Right now, there's no
logic for creating even straight corridors between rooms. Angled corridors will require more effort.&lt;/p&gt;
&lt;p&gt;Another early change will be the addition of non-rectangular rooms. This can include organic-looking
caverns, but also different regular rooms, like circular chambers.&lt;/p&gt;
&lt;p&gt;I plan on adding something else to the terrain, too - "lakes." In this case, lakes can refer to bodies
of water, but also pools of lava and bottomless chasms. These will have be carefully generated so that
they add character without cutting off sections of the dungeon.&lt;/p&gt;
&lt;h2 id="creatures-and-characters"&gt;Creatures and Characters&lt;/h2&gt;
&lt;p&gt;Mobs are divided into two types - creatures and characters. Anything that thinks requires creating two
resources in the system - a set of naming rules, and a species. Non-sentient things are classified
as creatures, and only require the addition of a single resource. The trouble is that most encounters
are comprised of characters. For the initial release of the dungeon generator, I added orcs, goblins,
and trolls. As far as the underlying system goes, they're equal to PC races like humans and elves.
I intend to keep it that way - they're not "monsters," they're just a different kind of thinking being.
This makes any added species useful in a wide variety of ways. They're not just for dungeon encounters.
They can be used in any system that uses characters.&lt;/p&gt;
&lt;p&gt;I plan on adding all of the common "monster" species in the near future. This includes, but is not limited to,
the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bugbears&lt;/li&gt;
&lt;li&gt;Centaurs&lt;/li&gt;
&lt;li&gt;Dark elves&lt;/li&gt;
&lt;li&gt;Deep dwarves (duergar)&lt;/li&gt;
&lt;li&gt;Deep gnomes&lt;/li&gt;
&lt;li&gt;Dragons (this one's difficult)&lt;/li&gt;
&lt;li&gt;Dryads&lt;/li&gt;
&lt;li&gt;Fairies&lt;/li&gt;
&lt;li&gt;Firbolgs&lt;/li&gt;
&lt;li&gt;Gnolls&lt;/li&gt;
&lt;li&gt;Gorgons&lt;/li&gt;
&lt;li&gt;Half-celestials (aasimar)&lt;/li&gt;
&lt;li&gt;Half-elementals (genasi)&lt;/li&gt;
&lt;li&gt;Hobgoblins&lt;/li&gt;
&lt;li&gt;Kobolds&lt;/li&gt;
&lt;li&gt;Lizardfolk&lt;/li&gt;
&lt;li&gt;Mind flayers&lt;/li&gt;
&lt;li&gt;Minotaurs&lt;/li&gt;
&lt;li&gt;Nymphs&lt;/li&gt;
&lt;li&gt;Ogres&lt;/li&gt;
&lt;li&gt;Pixies&lt;/li&gt;
&lt;li&gt;Satyrs&lt;/li&gt;
&lt;li&gt;Sea elves&lt;/li&gt;
&lt;li&gt;Serpentfolk (based on Yuan-ti)&lt;/li&gt;
&lt;li&gt;Troglodytes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, there are currently a few "templates" that can be applied to both creatures and characters.
Right now the list only consists of zombies, vampires, and skeletons. However, I plan on adding the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ghost&lt;/li&gt;
&lt;li&gt;Lich&lt;/li&gt;
&lt;li&gt;Werebear&lt;/li&gt;
&lt;li&gt;Weretiger&lt;/li&gt;
&lt;li&gt;Werewolf&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, the list of creatures is going to expand too. Eventually there will be a great many monsters from
a great many sources.&lt;/p&gt;
&lt;h2 id="locks-keys-and-treasure"&gt;Locks, Keys, and Treasure&lt;/h2&gt;
&lt;p&gt;At the moment, keys are only used for doors. I plan on making keys operate only on locks, and locks be
present in doors, chests, and other things. Like the existing keys, they will be populated in places
that don't make them unobtainable.&lt;/p&gt;
&lt;p&gt;Treasure is limited to coins only at the moment. The system that generates treasure needs a rewrite in
order to support mixed treasure piles. This won't be too difficult to implement. I already have gemstone
support written, even though it's not used yet. Art objects will be fairly straightforward. Magic items,
on the other hand, are going to be more difficult to implement. I plan on leaning on the existing magic
weapon generator for this. I also will need to build other types of magic item generators.&lt;/p&gt;
&lt;p&gt;All of these, incidentally, will be as system-neutral as possible. Like the dungeon generator itself though,
they'll be heavily informed by old school systems.&lt;/p&gt;
&lt;h2 id="closing-thoughts-and-other-things"&gt;Closing thoughts and other things&lt;/h2&gt;
&lt;p&gt;There is a lot of work that could be done that other generators have not yet. I won't promise anything
beyond what I've outlined above, but there are some interesting ideas that I want to explore. I'm
borrowing from the dungeon generation and population algorithms of roguelikes for some of this. After I
finish my entry for &lt;a href="https://www.reddit.com/r/rpg_generators/comments/v2mdaa/june_2022_generators_challenge_space/" rel="external"&gt;/r/rpg_generators' June 2022 challenge&lt;/a&gt;, I'll come back to the dungeon generator
and iterate more. Thanks for reading.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Tue, 07 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/06/iron-arachne-dungeon-generator/</guid></item><item><title>Bash compound commands and redirection</title><link>https://learnbyexample.github.io/mini/bash-compound-commands-redirection/</link><description>&lt;p&gt;I've been using Linux for about 15 years. There are a lot of features I don't know and some that I've used but not often enough or to the full extent of possibilities.&lt;/p&gt;
&lt;p&gt;Recently, I had written a &lt;code&gt;bash&lt;/code&gt; function, which required saving the output of a &lt;code&gt;for&lt;/code&gt; loop to a file. I knew that &lt;a href="https://www.gnu.org/software/bash/manual/bash.html#Compound-Commands"&gt;compound commands&lt;/a&gt; support &lt;a href="https://www.gnu.org/software/bash/manual/bash.html#Redirections"&gt;redirection&lt;/a&gt;, but it didn't strike me at that time as I haven't had to use them often.&lt;/p&gt;
&lt;p&gt;Here's a simplified version of the function I wrote first:&lt;/p&gt;
&lt;pre class="language-bash " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-bash"&gt;&lt;span style="color: #c23f31;"&gt;pf&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span&gt;{
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; input.txt
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for&lt;/span&gt;&lt;span&gt; f &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;$&lt;/span&gt;&lt;span style="color: #acb3c2;"&gt;@&lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;; do &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;$&lt;/span&gt;&lt;span style="color: #acb3c2;"&gt;f &lt;/span&gt;&lt;span style="color: #d07711;"&gt;$&lt;/span&gt;&lt;span style="color: #acb3c2;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;.bkp&amp;quot; &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; input.txt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;; done
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;cmd&lt;/span&gt;&lt;span&gt; input.txt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; output.txt
&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having to empty the file using &lt;code&gt;&amp;gt; input.txt&lt;/code&gt; got me thinking that perhaps I was missing some obvious solution. Few days later, I realized that instead of using &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; during every iteration of the loop, I should have just applied &lt;code&gt;&amp;gt;&lt;/code&gt; to the loop itself.&lt;/p&gt;
&lt;pre class="language-bash " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-bash"&gt;&lt;span style="color: #c23f31;"&gt;pf&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span&gt;{
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for&lt;/span&gt;&lt;span&gt; f &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;$&lt;/span&gt;&lt;span style="color: #acb3c2;"&gt;@&lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;; do &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;$&lt;/span&gt;&lt;span style="color: #acb3c2;"&gt;f &lt;/span&gt;&lt;span style="color: #d07711;"&gt;$&lt;/span&gt;&lt;span style="color: #acb3c2;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;.bkp&amp;quot; &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;; done &amp;gt;&lt;/span&gt;&lt;span&gt; input.txt
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;cmd&lt;/span&gt;&lt;span&gt; input.txt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; output.txt
&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; &lt;code&gt;echo&lt;/code&gt; and &lt;code&gt;cmd&lt;/code&gt; in the above examples are just placeholders for illustration purposes. I needed both &lt;code&gt;input.txt&lt;/code&gt; and &lt;code&gt;output.txt&lt;/code&gt; after calling the function, which is why I didn't use &lt;code&gt;|&lt;/code&gt; or process substitution.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Sat, 04 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/mini/bash-compound-commands-redirection/</guid></item><item><title>Why I Moved Off Dev.to</title><link>https://www.swyx.io/why-i-moved-off-devto</link><description>&lt;p&gt;2 years ago I &lt;a href="https://www.swyx.io/devto-cms"&gt;moved all my blogging to Dev.to&lt;/a&gt;. Today &lt;a href="https://www.swyx.io/github-cms"&gt;my main blog is on Github Issues&lt;/a&gt; and &lt;a href="https://twitter.com/swyx/status/1531330889535602688"&gt;I've just launched DXTips on Hashnode&lt;/a&gt;.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Wed, 01 Jun 2022 18:30:26 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/why-i-moved-off-devto</guid></item><item><title>Python tip 11: capture external command output</title><link>https://learnbyexample.github.io/tips/python-tip-11/</link><description>&lt;p&gt;The &lt;code&gt;subprocess&lt;/code&gt; module provides plethora of features to execute external commands, capturing output being one of them. There are two ways to do so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;passing &lt;code&gt;capture_output=True&lt;/code&gt; to &lt;code&gt;subprocess.run()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;subprocess.check_output()&lt;/code&gt; if you only want &lt;code&gt;stdout&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By default, results are provided as &lt;code&gt;bytes&lt;/code&gt; data type. You can change that by passing &lt;code&gt;text=True&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; import &lt;/span&gt;&lt;span&gt;subprocess
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;cmd &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'date'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'-u'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'+&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%A&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;p &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;run&lt;/span&gt;&lt;span&gt;(cmd, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;capture_output&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;text&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;p
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;CompletedProcess&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;args&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'date'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'-u'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'+&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%A&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;returncode&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0&lt;/span&gt;&lt;span&gt;,
&lt;/span&gt;&lt;span&gt;                 &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;stdout&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Wednesday&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\n&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;stderr&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;p.stdout
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Wednesday&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\n&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;check_output&lt;/span&gt;&lt;span&gt;(cmd, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;text&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Wednesday&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\n&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;check_output()&lt;/code&gt;, you'll get an exception if something goes wrong with the command being executed. With &lt;code&gt;run()&lt;/code&gt;, you'll get that information from &lt;code&gt;stderr&lt;/code&gt; and &lt;code&gt;returncode&lt;/code&gt; as part of the &lt;code&gt;CompletedProcess&lt;/code&gt; object.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;cmd &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ls'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'xyz.txt'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;run&lt;/span&gt;&lt;span&gt;(cmd, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;capture_output&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;text&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;CompletedProcess&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;args&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ls'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'xyz.txt'&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;returncode&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;stdout&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;''&lt;/span&gt;&lt;span&gt;,
&lt;/span&gt;&lt;span&gt;         &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;stderr&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;ls: cannot access 'xyz.txt': No such file or directory&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;\n&lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;subprocess.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;check_output&lt;/span&gt;&lt;span&gt;(cmd, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;text&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;ls: cannot access &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'xyz.txt'&lt;/span&gt;&lt;span&gt;: No such file &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;or &lt;/span&gt;&lt;span&gt;directory
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;Traceback &lt;/span&gt;&lt;span&gt;(most recent call last):
&lt;/span&gt;&lt;span&gt;  File &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;, line &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &amp;lt;&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;
&lt;/span&gt;&lt;span&gt;  File &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;/usr/lib/python3.8/subprocess.py&amp;quot;&lt;/span&gt;&lt;span&gt;, line &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;415&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;check_output
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;return &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;popenargs, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;stdout&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;PIPE&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;timeout&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span&gt;timeout, &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;check&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;=&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True&lt;/span&gt;&lt;span&gt;,
&lt;/span&gt;&lt;span&gt;  File &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;/usr/lib/python3.8/subprocess.py&amp;quot;&lt;/span&gt;&lt;span&gt;, line &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;516&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;run
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="background-color: #562d56bf; color: #f8f8f8;"&gt;raise&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;CalledProcessError&lt;/span&gt;&lt;span&gt;(retcode, process.args,
&lt;/span&gt;&lt;span&gt;subprocess.CalledProcessError: Command &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'('&lt;/span&gt;&lt;span&gt;ls&lt;/span&gt;&lt;span style="color: #d07711;"&gt;', '&lt;/span&gt;&lt;span&gt;xyz.txt&lt;/span&gt;&lt;span style="color: #d07711;"&gt;')' &lt;/span&gt;&lt;span&gt;returned
&lt;/span&gt;&lt;span&gt;                               non&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;zero exit status &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; You can also use legacy methods &lt;code&gt;subprocess.getstatusoutput()&lt;/code&gt; and &lt;code&gt;subprocess.getoutput()&lt;/code&gt; but they lack in features and do not provide secure options. See &lt;a href="https://docs.python.org/3/library/subprocess.html#legacy-shell-invocation-functions"&gt;docs.python: subprocess Legacy Shell Invocation Functions&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 01 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-11/</guid></item><item><title>What Happened with FPGA Acceleration?</title><link>https://specbranch.com/posts/fpgas-what-happened/</link><description>&lt;p&gt;In 2018, I took the jump from being primarily an FPGA hardware engineer to being primarily a software
engineer.  At the time, things were looking great for FPGA acceleration, with AWS and later Azure
bringing in VMs with FPGAs and the two big FPGA vendors setting their sights on application
acceleration. Almost 5 years later, I am working on another project with FPGAs, this time a
cloud-oriented one. That has inspired me to write a retrospective on the last 5 years of what we
thought would be an FPGA acceleration boom.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Wed, 01 Jun 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/fpgas-what-happened/</guid></item><item><title>Memex Rewind</title><link>https://mikewarot.blogspot.com/2022/05/memex-rewind.html</link><description>In 1945, the person in charge of research and development, who oversaw most of the science that won WWII with the help of Logistics, wrote an article about the most pressing task facing mankind, the need to organize and access the ever growing flood of information created by all of this activity.&lt;br /&gt;&lt;br /&gt;
His vision was expressed in an article titled "As We May Think", which was eventually republished by Time Magazine. Many people credit it for the vision that eventually became the world wide web. I also held this view for a long time.
&lt;br /&gt;&lt;br /&gt;I no longer hold that view. &lt;br /&gt;&lt;br /&gt;The web as we use it is about as useful as a picture of a box of tools, instead of the tools themselves. There was a vague notion expressed that you could gather up a huge canvas of inter-related thoughts and ideas, and freely associate them, and share the whole of that work effortlessly.
We don't have it. I'm trying to use my time and effort to change that by making something that gets a bit more of that toolset into my hands, and hopefully into everyone's eventually.&lt;br /&gt;&lt;br /&gt;Wish me luck.</description><author>--Mike--</author><pubDate>Tue, 31 May 2022 16:25:33 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/05/memex-rewind.html</guid></item><item><title>The Radiating Circles of DX Architecture</title><link>https://www.swyx.io/the-radiating-circles-of-dx-architecture</link><description>&lt;blockquote&gt;
&lt;p&gt;This post was originally published on my new dedicated DX site: https://dx.tips/circles&lt;/p&gt;
&lt;/blockquote&gt;</description><author>swyx's site RSS Feed</author><pubDate>Tue, 31 May 2022 00:56:12 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/the-radiating-circles-of-dx-architecture</guid></item><item><title>On OneStream</title><link>http://blog.pythonaro.com/2022/05/on-onestream.html</link><description>&lt;p&gt;If you follow &lt;a href="https://www.linkedin.com/in/glacava/" target="_blank"&gt;me on LinkedIn&lt;/a&gt;, you might have noticed that, about two years ago, I joined &lt;a href="https://onestreamsoftware.com/" target="_blank"&gt;OneStream&lt;/a&gt;.&lt;/p&gt;
&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgprludVrKqcaFLet9ZN1li-iNlMV9_leN_4TCqrtJzyiszuaC-oGVg9ytKNvmpxWNBropI2sra5BdMjxXDsOsthgYcmPnJf_R1YKF4fHbjyEKf55rjYxXwDgi4dfFwEFduaRq6tRWgYE8BAPEHIM3olxgkcvivunmTrX5Usv79CIf8E8hltA/s3568/cropped-OS-LogoTM-Horizontal-FC-RGB.webp" style="display: block; padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgprludVrKqcaFLet9ZN1li-iNlMV9_leN_4TCqrtJzyiszuaC-oGVg9ytKNvmpxWNBropI2sra5BdMjxXDsOsthgYcmPnJf_R1YKF4fHbjyEKf55rjYxXwDgi4dfFwEFduaRq6tRWgYE8BAPEHIM3olxgkcvivunmTrX5Usv79CIf8E8hltA/s320/cropped-OS-LogoTM-Horizontal-FC-RGB.webp" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
  
&lt;p&gt;I've since refrained from writing about it, for a number of reasons: the product is massive, so it took a while to get to grasp with it; my new role kinda constrained what I could talk about; and I thought I wasn't particularly well-qualified yet to speak about the subject.&lt;/p&gt;

&lt;p&gt;I recently attended the &lt;a href="https://splash.onestreamsoftware.com/" target="_blank"&gt;Splash&lt;/a&gt; conference for the first time. One of the things I brought home from San Antonio (together with a certain virus most people thought defeated) was the belief that, by now, I actually know a few things about OneStream - and there is a big hunger for that knowledge among clients and partners. The leadership is aware of this, so it was easy to get the greenlight on a few related projects.&lt;/p&gt;

&lt;p&gt;This means that I'll be writing a bunch of posts in the next couple of months, on OneStream-related subjects. They might not be published here, but wherever they end up, I'll make sure to link them from here. I'm a geek, not a marketer, so they will be technical posts about getting stuff done; there is already&lt;a href="https://onestreamsoftware.com/resources/" target="_blank"&gt; plenty of material on why you should use OneStream for your planning and financial consolidation needs&lt;/a&gt; - what people need is to learn &lt;b&gt;how&lt;/b&gt; you can do that, and that's where I'm going to help.&lt;/p&gt;

&lt;p&gt;In the meantime, if you'd like me to cover a particular topic, feel free to reach out (here, &lt;a href="https://www.linkedin.com/in/glacava/" target="_blank"&gt;on LinkedIn&lt;/a&gt;, or at my OneStreamSoftware.com address (glacava@).&lt;/p&gt;</description><author>Subclassed</author><pubDate>Mon, 30 May 2022 14:49:39 GMT</pubDate><guid isPermaLink="true">http://blog.pythonaro.com/2022/05/on-onestream.html</guid></item><item><title>Lessons in Competitive Comms from the Plaid-Stripe Kerfuffle</title><link>https://www.swyx.io/comms-plaid-stripe</link><description>&lt;p&gt;Now that the dust has settled on the Plaid-Stripe thing it's time to recap lessons learned.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sun, 29 May 2022 18:39:38 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/comms-plaid-stripe</guid></item><item><title>2022–05–29: Pinephone Pro camera pipeline testing app</title><link>https://xnux.eu/log/#069</link><author>megi's PinePhone Development Log</author><pubDate>Sun, 29 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#069</guid></item><item><title>More Data Scientists should learn SQL</title><link>https://bytepawn.com/more-data-scientists-should-learn-sql.html</link><description>&lt;p&gt;In my experience, many Data Scientists struggle to write SQL queries in interviews.&lt;br /&gt;&lt;br /&gt;&lt;img alt="SQL" src="/images/sql-img.jpg" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 29 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/more-data-scientists-should-learn-sql.html</guid></item><item><title>Running Docker without Docker Desktop</title><link>https://www.swyx.io/running-docker-without-docker-desktop</link><description>&lt;p&gt;Docker is great. Docker Desktop sucks. Here's my fix.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Fri, 27 May 2022 21:31:21 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/running-docker-without-docker-desktop</guid></item><item><title>marginalia.nu goes open source</title><link>https://www.marginalia.nu/log/58-marginalia-open-source/</link><description>&lt;p&gt;After a bit of soul searching with regards to the future of the website, I&amp;rsquo;ve decided to open source the code for marginalia.nu, all of its services, including the search engine, encyclopedia, memex, etc.&lt;/p&gt;
&lt;p&gt;A motivating factor is the search engine has sort of grown to a scale where it&amp;rsquo;s becoming increasingly difficult to productively work on as a personal solo project. It needs more structure. What&amp;rsquo;s kept me from open sourcing it so far has also been the need for more structure. The needs of the marginalia project, and the needs of an open source project have effectively aligned.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Fri, 27 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/58-marginalia-open-source/</guid></item><item><title>CLI tip 2: counting number of matches</title><link>https://learnbyexample.github.io/tips/cli-tip-2/</link><description>&lt;p&gt;Use &lt;code&gt;grep -c&lt;/code&gt; to count the number of input &lt;em&gt;lines&lt;/em&gt; containing a given pattern.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# number of input lines containing 'a'
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# number of input lines containing all the vowels
&lt;/span&gt;&lt;span&gt;$ grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;icP &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'^(?=.*a)(?=.*e)(?=.*i)(?=.*o).*u' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span&gt;usr&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span&gt;share&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span&gt;dict&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span&gt;words
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;640
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# number of input lines NOT containing 'at'
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;vc &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'at'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With multiple file input, count is displayed for each file &lt;em&gt;separately&lt;/em&gt;. Use &lt;code&gt;cat&lt;/code&gt; if you need a combined count.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# separate count for each input file
&lt;/span&gt;&lt;span&gt;$ grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a'&lt;/span&gt;&lt;span&gt; names.txt purchases.txt 
&lt;/span&gt;&lt;span&gt;names.txt&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2
&lt;/span&gt;&lt;span&gt;purchases.txt&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# total count for all the input files
&lt;/span&gt;&lt;span&gt;$ cat names.txt purchases.txt &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'a'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If total number of matches is required, use the &lt;code&gt;-o&lt;/code&gt; option to display only the matching portions (one per line) and then use &lt;code&gt;wc&lt;/code&gt; to get the count.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# -c gives count of matching lines only
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'[aeiou]'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# use -o to get each match on a separate line
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;o &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'[aeiou]' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; wc &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;l
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Note that if you use &lt;a href="https://github.com/BurntSushi/ripgrep"&gt;ripgrep&lt;/a&gt;, you can simply use &lt;code&gt;-co&lt;/code&gt; or &lt;code&gt;--count-matches&lt;/code&gt; instead of piping to the &lt;code&gt;wc&lt;/code&gt; command.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# this behavior is different compared to GNU grep
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'goal\nrate\neat\npit' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; rg &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;co &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'[aeiou]'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/learn_gnugrep_ripgrep"&gt;CLI text processing with GNU grep and ripgrep&lt;/a&gt; ebook if you are interested in learning about &lt;code&gt;GNU grep&lt;/code&gt; and &lt;code&gt;ripgrep&lt;/code&gt; commands in more detail.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 27 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-2/</guid></item><item><title>Vim tip 9: named registers</title><link>https://learnbyexample.github.io/tips/vim-tip-9/</link><description>&lt;p&gt;In Normal mode, you can use lowercase alphabets &lt;code&gt;a-z&lt;/code&gt; to save some content for future use. You can also append some more content to those registers by using the corresponding uppercase alphabets &lt;code&gt;A-Z&lt;/code&gt; at a later stage.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;&amp;quot;ayy&lt;/kbd&gt; copy the current line to the &lt;code&gt;&amp;quot;a&lt;/code&gt; register&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;&amp;quot;bdip&lt;/kbd&gt; delete the current paragraph, contents will also be saved to the &lt;code&gt;&amp;quot;b&lt;/code&gt; register&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;&amp;quot;Ayj&lt;/kbd&gt; append the current line and the line below to the &lt;code&gt;&amp;quot;a&lt;/code&gt; register
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;&amp;quot;ayy&lt;/kbd&gt; followed by &lt;kbd&gt;&amp;quot;Ayj&lt;/kbd&gt; will result in total three lines in the &lt;code&gt;&amp;quot;a&lt;/code&gt; register&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;&amp;quot;ap&lt;/kbd&gt; paste content from the &lt;code&gt;&amp;quot;a&lt;/code&gt; register&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;&amp;quot;eyiw&lt;/kbd&gt; copy word under the cursor to the &lt;code&gt;&amp;quot;e&lt;/code&gt; register&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; You can use &lt;kbd&gt;:reg&lt;/kbd&gt; (short for &lt;code&gt;:registers&lt;/code&gt;) to view the contents of the registers. Specifying one or more characters (next to each other as a single string) will display contents only for those registers.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; The named registers are also used for saving macros. You can record an empty macro to clear the contents, for example &lt;kbd&gt;qbq&lt;/kbd&gt; clears the &lt;code&gt;&amp;quot;b&lt;/code&gt; register.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 24 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-9/</guid></item><item><title>My 2022 New Mac Setup</title><link>https://www.swyx.io/new-mac-setup-2022</link><description>&lt;p&gt;I set up a new Mac for work today. Here's everything I use on a Mac for fullstack web development.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Mon, 23 May 2022 01:03:12 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/new-mac-setup-2022</guid></item><item><title>2022–05–22: Pinephone Pro camera improvements</title><link>https://xnux.eu/log/#068</link><author>megi's PinePhone Development Log</author><pubDate>Sun, 22 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#068</guid></item><item><title>2022–05–22: Pinephone Pro cameras kernel support</title><link>https://xnux.eu/log/#067</link><author>megi's PinePhone Development Log</author><pubDate>Sun, 22 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#067</guid></item><item><title>Useful Python decorators for Data Scientists</title><link>https://bytepawn.com/python-decorators-for-data-scientists.html</link><description>&lt;p&gt;I show toy implementations of Python decorator patterns that may be useful for Data Scientists.&lt;br /&gt;&lt;br /&gt;&lt;img alt="Python decorators" src="/images/decorators-ds.jpg" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 22 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/python-decorators-for-data-scientists.html</guid></item><item><title>Teach Your Kids Bridge</title><link>https://specbranch.com/posts/teach-bridge/</link><description>&lt;p&gt;A post recently made the rounds on &lt;a href="https://news.ycombinator.com/news"&gt;hacker news&lt;/a&gt; claiming that
&lt;a href="https://momentofdeep.substack.com/p/teach-your-kids-poker-not-chess?s=r"&gt;you should teach your kids poker, not chess&lt;/a&gt;.
The comments on that post go through a lot of the reasons why poker is a bad game to teach your
children, but I felt that I was well suited to opine on this topic, and explain why duplicate
bridge is the best game for practicing the life skills involved in business and programming,
compared to all of the alternatives.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Sat, 21 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/teach-bridge/</guid></item><item><title>Traveling light</title><link>https://blog.bayindirh.io/blog/traveling-light/</link><description>&lt;p&gt;I had to travel recently for a conference, and I decided to apply what I've learned about minimalism so far.&lt;/p&gt;
&lt;p&gt;Traveling as a tech person means carrying more electronics and peripherals than most people, and things can get complicated and heavy quickly. This time, I tried to prevent that, and I succeeded.&lt;/p&gt;
&lt;p&gt;Since it's a work-related conference, my office laptop came with me, which is small and can be charged with a 30W USB-C charger. Also, a portable 4G modem, a power bank, an e-book reader, and a phone took the ride with me.&lt;/p&gt;
&lt;p&gt;That meant a lot of chargers and cables before.&lt;/p&gt;
&lt;p&gt;To my surprise, all the peripherals needed for this arsenal of devices can be reduced to a 2-port charger and two cables. That was unimaginable until recently. That removes a lot of volume and weight from the backpack, making it much easier to haul around both on the plane and at the destination. While we still have &lt;a href="https://xkcd.com/927/"&gt;15 competing standards&lt;/a&gt; for these things, the devices use a small subset of these. Convergence is good.&lt;/p&gt;
&lt;p&gt;It's worth noting that the cables and charger are aftermarket items. While this adds another cost item, their long life, daily use, and the convenience they bring are incomparable to this cost. As I've noted before, minimalism and frugality &lt;a href="https://blog.bayindirh.io/blog/on-minimalism-and-frugality/"&gt;need not be the same thing&lt;/a&gt; but, these one-time costs become negligible if the item has a meaningful lifetime.&lt;/p&gt;
&lt;p&gt;In my opinion, peace of mind is priceless.&lt;/p&gt;
&lt;p&gt;On the luggage side, I took a similar approach. Reducing what's packed to bare essentials and adding extras for critical items only saved a lot of space and weight. That, in turn, enabled me to fly without checked luggage and saved me a lot of time at the airport. I'm not a person who carries everything and the kitchen sink everywhere, but making small changes had a much greater impact than I anticipated.&lt;/p&gt;
&lt;p&gt;Another nice side-effect is the time I've saved while packing. Fewer items, less thinking, less hauling, and importantly, much less stress and anxiety.&lt;/p&gt;
&lt;p&gt;That is precisely the thing &lt;a href="https://blog.bayindirh.io/blog/meditations-on-minimalism/"&gt;that I wanted to achieve&lt;/a&gt; when I started exploring minimalism.&lt;/p&gt;
&lt;p&gt;I'm starting to see the results I hoped to achieve with minimalism, but I'm at the beginning of my journey. I'm sure that as I go deeper, I'm going to meet with issues I've never thought about before, but that part comes later for now.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Thu, 19 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/traveling-light/</guid></item><item><title>Unfinished Business with Postgres</title><link>/2022/05/18/Unfinished-Business-with-Postgres/</link><description>&lt;p&gt;7 years ago I left Heroku. Heroku has had a lot of discussion over the past weeks about its demise, whether it was a &lt;a href="https://twitter.com/sraney/status/1519516583042818049"&gt;success&lt;/a&gt; or failure, and the current state. Much of this was prompted by the recent, and on-going security incident, but as others have pointed out the product has been frozen in time for some years now.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not here to rehash the many debates of what is the next Heroku, or whether it was a &lt;a href="https://news.ycombinator.com/item?id=31373300"&gt;success&lt;/a&gt; or failure, or how it could have been &lt;a href="https://news.ycombinator.com/item?id=31373394"&gt;different&lt;/a&gt;. Heroku is still a gold standard of developer experience and often used in pitches as Heroku for X. There were many that tried to imitate Heroku for years and failed. Heroku generates sizable revenue to this day. &lt;a href="https://twitter.com/_adamwiggins_/status/1334595784373923840"&gt;Without Heroku&lt;/a&gt; we’d all be in a worse place from a developer experience perspective.&lt;/p&gt;
&lt;p&gt;But I don’t want to talk about Heroku the PaaS. Instead I want share a little of my story and some of the story of Heroku Postgres (DoD - Department of Data as we were internally known). I was at Heroku in a lot of product roles over the course of 5 yrs, but most of my time was with that DoD team. When I left Heroku it was a team of about 8 engineers running and managing over 1.5m Postgres databases–a one in a million problem was once a week, we engineered a system that allowed us to scale without requiring a 50 person ops team just for databases&lt;/p&gt;
&lt;p&gt;This will be a bit of a personal journey, but also hopefully give some insights into what the vision was and hopefully a bit of what possibilities are for Postgres services in the future.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I wasn&amp;rsquo;t originally hired to work on anything related to Postgres.&lt;/em&gt; As an early PM I first worked on billing, then later on core languages and launching the Python support for Heroku. It was a few months in when I found myself having conversations with many of the internal engineers about Postgres. &amp;ldquo;Why aren&amp;rsquo;t you using hstore?&amp;rdquo;, &amp;ldquo;Transactional DDL to rollback transactions is absolutely huge!&amp;rdquo;, &amp;ldquo;Concurrent index creation runs in the background while not holding a lock, this should always be how you add an index.&amp;rdquo; Now we had some great engineers, but it was the typical engineer that interacted through ActiveRecord and didn&amp;rsquo;t want to think about the database.&lt;/p&gt;
&lt;p&gt;As I found myself &lt;a href="https://www.craigkerstiens.com/2012/04/30/why-postgres/"&gt;evangelizing Postgres&lt;/a&gt;, suddenly I was being recruited by the lead of the Postgres team to come and do marketing, I didn&amp;rsquo;t know anything about marketing and thought they were joking. A couple months later found myself doing PM and marketing for DoD.&lt;/p&gt;
&lt;h3 id="why-did-heroku-pick-postgres"&gt;
&lt;div&gt;
Why did Heroku pick Postgres?
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;But, I&amp;rsquo;m getting a little bit ahead of myself. How did Heroku even start doing Postgres or why? Running a PaaS (platform as a service) is a lot of work, running a database is a lot of work. In some sense doing both is splitting your focus. And I&amp;rsquo;m increasingly coming to the conclusion that platform companies will do best to &lt;a href="https://news.ycombinator.com/item?id=31185715"&gt;focus&lt;/a&gt; on their platform and data companies will do best to focus on the data. Well, way back in the day we had all these Rails developers asking for a database and we thought how hard could it be? (It was more work than we expected). So we&amp;rsquo;re gonna run a database, the question becomes which one? Most folks didn&amp;rsquo;t have strong opinion, but one of our security/ops engineers chimed in &amp;ldquo;Postgres has always had a good record of being safe and reliable for data, I&amp;rsquo;d go with it.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;And with that, we were building and launching Heroku Postgres.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The first version of Heroku Postgres, no automation, no self service provisioning, you opened a ticket and we’d correspond and ask when you wanted us to set it up for you.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="before-heroku-postgres-was-postgres"&gt;
&lt;div&gt;
Before Heroku Postgres was Postgres
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;The very first version before we committed to Heroku Postgres was internally known as Shen. The model was much more akin to shared hosting that was common for that time and place. Within a single instance we’d pack in a lot of Postgres databases, simply running createdb, creating a user for you, then giving you access to that DB. This worked fine for those just kicking the tires and building small apps, but despite telling them to not use it for production people continued to.&lt;/p&gt;
&lt;p&gt;While Heroku had Postgres before Heroku Postgres it became a project and its own orchestration layer for databases as a more first class citizen around 2010. The initial codename for the project was &amp;ldquo;&lt;a href="https://gist.github.com/adamwiggins/7d0e0805e0e44870f17f"&gt;bifrost&lt;/a&gt;&amp;rdquo;.&lt;/p&gt;
&lt;h3 id="the-original-design"&gt;
&lt;div&gt;
The original design
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;Heroku Postgres was designed to have a central FSM (finite state machine) that would orchestrate the databases. This design pattern to my knowledge came from &lt;a href="https://www.twitter.com/pvh"&gt;@PvH&amp;rsquo;s&lt;/a&gt; work and appreciation of video game system design. It felt like a novel approach to the software being built at this time. The fact that it is a more common design patten now shows what a great design it was, and how ahead of its time the level that team was building at.&lt;/p&gt;
&lt;p&gt;It was a basic Ruby application that would go out and check the state databases and go through the needed steps when interacting with either Postgres or AWS APIs. AWS APIs back then were not what they are now and this allowed to build in necessary retries, redundancies, and quality of service.&lt;/p&gt;
&lt;h3 id="sometimes-youre-good-sometimes-youre-lucky"&gt;
&lt;div&gt;
Sometimes you&amp;rsquo;re good, sometimes you&amp;rsquo;re lucky
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;Sometimes you&amp;rsquo;re good, sometimes you&amp;rsquo;re lucky, sometimes it&amp;rsquo;s both. Over time we built out more reliable provisioning and monitoring of databases. In early 2011 we felt a need to continue improving this. It was the early days of EC2 and reliability wasn&amp;rsquo;t the strongest spot, instances could go offline.&lt;/p&gt;
&lt;p&gt;Per &lt;a href="https://www.twitter.com/danfarina"&gt;@danfarina&lt;/a&gt; &amp;ldquo;We were thinking about working on replication but skipping over archiving (by more carefully managing state between servers, e.g. by directly moving things through rsync, which was/is still pretty normed postgres stuff predating pg_basebackup) but then one of the shared databases (shen) had a near miss when a disk was lost that caused a rather horrific amount of effort and some nailbiting in restoring from pgbackups.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;We then decided to take previouly rejected approach of building everything up on the archives. the first versions were s3cmd based, and were something of a prototype, upon request from PvH to ship something more raw, but more quickly. We had just got early versions into production when the &lt;a href="https://aws.amazon.com/message/65648/"&gt;major disk apocalypse&lt;/a&gt; hit in April 2011, though it was in something of an evaluation period and it was not yet a well-exercised &amp;amp; monitored program, so we crossed our fingers and, thankfully, it worked on every database, once AWS had capacity to spare.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;At the end of the event it was communicated eventually that if we wanted AWS could give us all of the EBS disks back, but it could be all of them were corrupted. As someone we can’t recall adequately described it: &amp;ldquo;It’s like getting a gallon of ice cream, but it may have a turd in it&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;More from @danfarina: &amp;ldquo;Were it up to me at the time, I probably would have moved onto converting it to boto (one of the most mature AWS client bindings at the time, by far) before stopping to deploy the s3cmd near-prototype on every instance, but that would have been a disaster.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Our applications were resilient because we could leverage multiple dynos and the routing layer available to our system. Databases are a little different, but how could we at scale give the features you most needed for a database:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;No data loss&lt;/li&gt;
&lt;li&gt;Improved availability&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Number one was always a core charter for the team and we would prioritize this over features, and over uptime. Uptime mattered, features mattered, but as a data provider if we lost data we&amp;rsquo;d lose trust. Thus that quick prototype became wal-e, which then went on to power many of the future features of Heroku Postgres, and be used for many years, though now has been deemed obsolete in favor of more modern tooling such as &lt;a href="https://pgbackrest.org/"&gt;pgBackRest&lt;/a&gt;. But for it’s time and place it was some good execution and some luck on timing.&lt;/p&gt;
&lt;h3 id="thinking-about-the-entire-experience"&gt;
&lt;div&gt;
Thinking about the entire experience
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;As Heroku sat at a central point of app deployment we actively tried to think about the experience end to end. This manifested in some of the small things we actively campaigned for and collaborated with the community members who could make these happen. A few key examples come to mind for this.&lt;/p&gt;
&lt;p&gt;The first was &lt;code&gt;DATABASE_URL&lt;/code&gt;. Some of this originated from the &lt;a href="https://12factor.net"&gt;12factor concepts&lt;/a&gt;, others in that having 5 environment variables to define what you were connecting too felt verbose and cumbersome. Why couldn’t Rails just use &lt;code&gt;DATABASE_URL&lt;/code&gt; if it were defined. I don’t recall the specifics here, but suspect this was something we nudged &lt;a href="https://www.twitter.com/hone02"&gt;@hone02&lt;/a&gt; to help with.&lt;/p&gt;
&lt;p&gt;The second was around some features of Postgres. At the time Postgres was going well, but most of the core community focused on performance or enterprise-y features. We were coming at it from a different angle with an audience of Rails developers. We were intentional and engaged with some of the Postgres consultancies that employed committers, with a general theme of how can we help contribute, while also advancing Postgres based on the knowledge we have from users. A few highlights here included:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Not just the &lt;code&gt;DATABASE_URL&lt;/code&gt; on the Rails side, but also on the native libpq wire protocol. While we didn’t do the work here, we were spent notable time &lt;a href="https://www.postgresql.org/message-id/CAAcg%3DkWxsUeQ7Rz%3Dto4nvuwHJ%2BVj6ADrNHEcqFrGHnYmMNPznQ%40mail.gmail.com"&gt;advocating and engaging&lt;/a&gt; around it.&lt;/li&gt;
&lt;li&gt;pg_stat_statements in my opinion now the most valuable Postgres extension existed before, but was effectively unusable for most applications. Funding this work was foundational to make Postgres have more usable insights natively.&lt;/li&gt;
&lt;li&gt;JSON/JSONB collaboration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Of note we later hired several contributors to largely focus their time on upstream Postgres itself.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="dataclips-vs-the-team"&gt;
&lt;div&gt;
Dataclips vs. the team
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;Throughout the history of Heroku Postgres various individuals made a series of bets. First it was @PvH pushing for Wal-E to get out the door as an MVP, which was absolutely the right call in retrospect. Perhaps the one that is most exciting to me and people least associate with Heroku is dataclips. &lt;a href="https://twitter.com/mattsoldo"&gt;Matt Soldo&lt;/a&gt;, had this idea of GitHub Gists for your database. But in the early days of Heroku as a PM, like many places as PM you didn’t have an ease to mandate engineers try a thing. You had to campaign and convince for a thing.&lt;/p&gt;
&lt;p&gt;Soldo didn’t build up enough buy in from the team, but had done plenty of awesome things that it was worth letting him run with this. We were all wrong. Dataclips was built by an external consulting company as a separate standalone Heroku app. It was only live for weeks and suddenly it was powering all of our internal dashboards. A live query you could embed into google sheets, suddenly our internal KPI rails app was replaced by dataclips and a google sheet. We didn’t need looker or tableau or other fancy BI tools and this lasted into 100m in revenue for insights into the business. To this day dataclips is one of my favorite features of Heroku, and I look forward to making an experience like that but even better, thanks Soldo for not listening to the rest of us back then.&lt;/p&gt;
&lt;h3 id="names-matter"&gt;
&lt;div&gt;
Names matter
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;For a long time databases haven&amp;rsquo;t been known for being user friendly. We wanted to pull from other paradigms as we were making key database tenets available to people. We looked heavily to git for inspiration around forking/following. Database terms were common as master/slave, but we knew we could do better. Ee wanted to give the user a sense of what they could do with it. Archiving the WAL every 16 MB or 60 seconds (whichever was less) became continuous protection. Forking, was a snapshot as of some point in time. Follower, something that followers a leader node (a read-replica). I still recall an hour long analyst call with Redmonk with &lt;a href="https://www.twitter.com/monkchips"&gt;@monkchips&lt;/a&gt; and &lt;a href="https://www.twitter.com/sogrady"&gt;@sogrady&lt;/a&gt;–it was mostly wind them up and let them go (for the record &lt;a href="https://www.twitter.com/monkchips"&gt;@monkchips&lt;/a&gt; didn&amp;rsquo;t love fork/follow, I think he may have come around now).&lt;/p&gt;
&lt;p&gt;This started even earlier than my time with being intentional about Postgres vs. PostgreSQL. But I’ve covered that one &lt;a href="https://www.craigkerstiens.com/2018/10/30/postgres-biggest-mistake/"&gt;before&lt;/a&gt;, and you can even see it in some of the other lobbying around &lt;a href="https://www.postgresql.org/message-id/CAAcg%3DkWxsUeQ7Rz%3Dto4nvuwHJ%2BVj6ADrNHEcqFrGHnYmMNPznQ%40mail.gmail.com"&gt;libpq&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="peacetime-vs-wartime"&gt;
&lt;div&gt;
Peacetime vs. Wartime
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;Things were rolling along well, we were shipping new features. We&amp;rsquo;d added dataclips, fork/follow were in existence for a while–and then we got a note from Amazon they were launching Postgres support for RDS at the next ReInvent. I was in person at that ReInvent and I&amp;rsquo;d never seen a roaring standing applause like that at a tech conference before when the moment was announced. In private channels we heard notes that this was because of us, the excitement and demand for Postgres became too clear for them to ignore and they had to add support.&lt;/p&gt;
&lt;p&gt;We felt vindicated in our choice of Postgres and in what we&amp;rsquo;d built. But we also knew that now we had competition, running a database as a service on another infrastructure provider how can you compete? Well from some years of experience now I can say there are definitely ways and am confident that sharp narrow focus allows you to build amazing products which can be harder to do inside a large giant corporation. It was at one of &lt;a href="https://www.postgresql.org/docs/9.1/datatype-datetime.html#DATATYPE-DATETIME-SPECIAL-TABLE"&gt;allballs&lt;/a&gt; (UTC 00:00:00-when the data team would do happy hour on Fridays) that we were drinking beers and discussing how now we really had to focus. @&lt;a href="https://www.twitter.com/pvh"&gt;PvH&lt;/a&gt; and @&lt;a href="https://www.twitter.com/danfarina"&gt;danfarina&lt;/a&gt; were discussing me personally as a leader–apparently I&amp;rsquo;m okay in peacetime when things are good but in wartime they were willing to bet on me.&lt;/p&gt;
&lt;p&gt;Two weeks later I walked into the exec team meeting with a 2-pager assessment of what may happen, how we could compete, including 3 potential acquisition targets that could allow us to have a more differentiated offering. Within a few months we made one of those acquisitions which later became Heroku Connect. It made a lot of sense for many reasons, including &lt;a href="https://www.twitter.com/adam_g"&gt;Adam Gross&lt;/a&gt; was an angel investor in Heroku and knew it well and had helped build Salesforce Platform in early years. That wasn&amp;rsquo;t the end, but was just the beginning of how we could actively compete vs. simply being &amp;ldquo;hosted Postgres&amp;rdquo; vs. a more fully managed experience.&lt;/p&gt;
&lt;h3 id="metrics-and-monitoring-that-almost-was"&gt;
&lt;div&gt;
Metrics and Monitoring that almost was
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;The next vision and goal for Heroku Postgres was to continue to give better ease of use and insights into your database. Postgres itself already has a ton of awesome data inside it about how it’s been used. The catalog tables and extensions like &lt;code&gt;pg_stat_statements&lt;/code&gt; have a wealth of information, but querying it looks like 200 lines of black magic SQL. &lt;a href="https://www.twitter.com/leinweber"&gt;@leinweber&lt;/a&gt; was perhaps one of the first, and the best at the team and quickly making something usable for people. The first step on our metrics journey was him making these Postgres insights trivially accessible via &lt;a href="https://blog.heroku.com/more_insight_into_your_database_with_pgextras"&gt;pg-extras&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Continuing on the journey internal foundational systems were built, in fact we just spent 3 months &lt;a href="https://www.crunchydata.com"&gt;@crunchydata&lt;/a&gt; building similar systems that were spiritually aligned, to focus on collection of various meta data from systems and the ability to notify and communicate. I’m blanking on some of the systems, though some were obvious–observatory (I’m not sure if still in use or not) would observe databases.&lt;/p&gt;
&lt;p&gt;These systems started to house a lot of information that then powered pieces within your Heroku Postgres dashboard. Things like slow queries and high IO or CPU load would give good insights when you logged in. The eventual goal was to connect the dots through proactive notifications. It’s one thing to get an alert from pagerduty that things are off, login to a dashboard and fix it. But what if in the early signs of things starting to go south we emailed you that you’ve got an increasing number of sequential scans that are starting to put you at risk of IOPS saturation, and because we understand Postgres you can add an index and resolve this with a single command. We could even give you an easy button in your email to add the index. All the foundations were in place, if you’ve run on Heroku you’ve gotten the notifications about database maintenance, that was powered entirely from the underlying notification system built with this goal in mind.&lt;/p&gt;
&lt;h3 id="postgres-can-still-be-better-for-developers"&gt;
&lt;div&gt;
Postgres can still be better for developers
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;But we never made it there. Some of us shuffled to different teams, some of us moved on to new challenges, and many folks came on after to continue to run and power a great database service. Some of those original engineers Daniel Farina and Will Leinweber (along with PvH) understand the design and why as well as anyone. The goal from early on was that we could do better for developers.&lt;/p&gt;
&lt;p&gt;Two years ago when people asked why I came to &lt;a href="https://www.crunchydata.com"&gt;Crunchy Data&lt;/a&gt; I told them I had unfinished business. After the success at Citus tackling scalability problems where the average customer being 40TB in data, I attracted to the idea of returning to the vision we had back at the DoD of bringing a better Postgres experience to developers. Despite the rapid growth of successful DBaaS offerings, there was still something missing - that initial idea of DoD that we still wanted to create.&lt;/p&gt;
&lt;p&gt;Postgres is an amazing database, can handle hundreds of thousands of transactions per second often without batting an eye. Has internal data that you can easily look at to assess and improve performance. Has a rich set of datatypes, indexing, and functionality. The extension ecosystem is vast. But as a developer you don’t have time to become an expert on Postgres.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What if we told you when a N+1 query snuck into your Rails app?&lt;/li&gt;
&lt;li&gt;Connections don’t have to be a limitation on Postgres when you have pgBouncer right there.&lt;/li&gt;
&lt;li&gt;Have excessive indexes from the early stage of building your app? What if we told you about them and with a button click you could drop them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One of our &lt;a href="https://www.twitter.com/crunchydata"&gt;@crunchydata&lt;/a&gt; customers described it better than I ever could. When working with some of our experts on some deep dives into their database they said “you should take all his Postgres expertise and just bottle it up and send it in email or slack reports to me.” I want that expertise as a &lt;a href="https://crunchybridge.com/register"&gt;product&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My product strategy isn’t to go and change the world of databases. Postgres is a great database with a community that is making it better daily. I want to help make open source Postgres better and give back to it along the way. My product strategy is to distribute deep Postgres expertise in a consumable form to every customer of ours in the coming years. Oh we’ll ship some cool things along the way too.&lt;/p&gt;</description><author>CRAIG KERSTIENS</author><pubDate>Wed, 18 May 2022 19:52:56 GMT</pubDate><guid isPermaLink="true">/2022/05/18/Unfinished-Business-with-Postgres/</guid></item><item><title>Fixed Point Arithmetic</title><link>https://specbranch.com/posts/fixed-point/</link><description>&lt;p&gt;When we think of how to represent fractional numbers in code, we reach for &lt;code&gt;double&lt;/code&gt; and &lt;code&gt;float&lt;/code&gt;,
and almost never reach for anything else.  There are several alternatives, including
&lt;a href="https://dl.acm.org/doi/pdf/10.1145/2911981"&gt;constructive real numbers&lt;/a&gt; that are used in calculators,
and &lt;a href="https://docs.python.org/3/library/fractions.html"&gt;rational numbers&lt;/a&gt;.  One alternative predates
all of these, including floating point, and actually allows you to compute faster than when you
use floating point numbers.  That alternative is fixed point: a primitive form of decimal that does
not offer any of the conveniences of &lt;code&gt;float&lt;/code&gt;, but allows you to do decimal computations more quickly
and efficiently. Fixed point still has usage in some situations today, and it can be a potent tool
in your arsenal as a programmer if you find yourself working with math at high speed.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Wed, 18 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/fixed-point/</guid></item><item><title>Firefox Addons for 2022</title><link>https://smcleod.net/2022/05/firefox-addons-for-2022/</link><description>&lt;!-- markdownlint-disable MD025 --&gt;
&lt;h2 id="firefox-addons---2022-edition"&gt;Firefox Addons - 2022 Edition&lt;/h2&gt;
&lt;p&gt;My list of must-have Firefox addons - 2022 edition&lt;/p&gt;
&lt;p&gt;Updated: 2022-11-07&lt;/p&gt;
&lt;h3 id="privacy-and-security"&gt;Privacy and Security&lt;/h3&gt;
&lt;p&gt;Firstly - you should have &lt;a href="https://support.mozilla.org/en-US/kb/enhanced-tracking-protection-firefox-desktop"&gt;Firefox&amp;rsquo;s Enhanced Tracking Protection&lt;/a&gt; enabled.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-GB/firefox/addon/dont-track-me-google1"&gt;Don&amp;rsquo;t Track Me Google&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-GB/firefox/addon/localcdn-fork-of-decentraleyes/"&gt;LocalCDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-GB/firefox/addon/utm-tracking-token-stripper"&gt;UTM Tracking Token Stripper&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Note: You can accomplish some of what this does by setting up the &lt;code&gt;removeparam&lt;/code&gt; uBlock origin rules I&amp;rsquo;ve listed below.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-GB/firefox/addon/multi-account-containers"&gt;Multi-Account Containers&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Useful for setting sites such as Amazon, eBay, Twitter, LinkedIn, Banking etc&amp;hellip; each to always open in their own isolated container.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The official addon for whatever Password Manager you use.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://browser.mt/"&gt;Firefox Translations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="ublock-origin"&gt;uBlock Origin&lt;/h4&gt;
&lt;p&gt;Probably the single most important addon.&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Tue, 17 May 2022 11:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2022/05/firefox-addons-for-2022/</guid></item><item><title>Linux compared to Window 11 in terms of suckage</title><link>https://mikewarot.blogspot.com/2022/05/linux-compared-to-window-11-in-terms-of.html</link><description>&lt;p&gt;&amp;nbsp;I came across &lt;a href="https://youtu.be/DEBQLjGJi2g?t=163" target="_blank"&gt;this comparison video&lt;/a&gt;, and it makes a comparison of features between Pop Linux and Windows 11 For the most part, they're equivalent.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description><author>--Mike--</author><pubDate>Tue, 17 May 2022 08:09:42 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/05/linux-compared-to-window-11-in-terms-of.html</guid></item><item><title>Let's build a distributed Postgres proof of concept</title><link>http://notes.eatonphil.com/distributed-postgres.html</link><description>&lt;p&gt;What is CockroachDB under the hood? Take a look at
&lt;a href="https://github.com/cockroachdb/cockroach/blob/master/go.mod"&gt;its go.mod&lt;/a&gt;
and notice a number of dependencies that do a lot of work: &lt;a href="https://github.com/jackc/pgproto3"&gt;a
PostgreSQL wire protocol
implementation&lt;/a&gt;, &lt;a href="https://github.com/cockroachdb/pebble"&gt;a storage
layer&lt;/a&gt;, &lt;a href="https://github.com/etcd-io/etcd"&gt;a Raft implementation
for distributed consensus&lt;/a&gt;. And not
part of go.mod but still building on 3rd party code, &lt;a href="https://github.com/cockroachdb/cockroach/blob/master/pkg/sql/parser/sql.y"&gt;PostgreSQL's
grammar
definition&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To be &lt;em&gt;absurdly&lt;/em&gt; reductionist, CockroachDB is just the glue around these
libraries. With that reductionist mindset, let's try building a
distributed Postgres proof of concept ourselves! We'll use only four
major external libraries: for parsing SQL, handling Postgres's wire
protocol, handling Raft, and handling the storage of table metadata
and rows themselves.&lt;/p&gt;
&lt;p class="note"&gt;
  For a not-reductionist understanding of the CockroachDB internals, I
  recommend following the
  excellent &lt;a href="https://www.cockroachlabs.com/blog/"&gt;Cockroach
  Engineering blog&lt;/a&gt;
  and &lt;a href="https://www.twitch.tv/large__data__bank"&gt;Jordan Lewis's
  Hacking CockroachDB Twitch stream&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;By the end of this post, in around 600 lines of code, we'll have a
distributed "Postgres implementation" that will accept writes
(&lt;code&gt;CREATE TABLE&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;) on the leader and accept reads (&lt;code&gt;SELECT&lt;/code&gt;)
on any node. All nodes will contain the same data.&lt;/p&gt;
&lt;p&gt;Here is a sample interaction against the leader:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;psql&lt;span class="w"&gt; &lt;/span&gt;-h&lt;span class="w"&gt; &lt;/span&gt;localhost&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6000&lt;/span&gt;
psql&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;.4,&lt;span class="w"&gt; &lt;/span&gt;server&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.0.0&lt;span class="o"&gt;)&lt;/span&gt;
Type&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;help.

&lt;span class="nv"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;table&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;age&lt;span class="w"&gt; &lt;/span&gt;int,&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
CREATE&lt;span class="w"&gt; &lt;/span&gt;ok
&lt;span class="nv"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;insert&lt;span class="w"&gt; &lt;/span&gt;into&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;values&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'garry'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'ted'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
could&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;interpret&lt;span class="w"&gt; &lt;/span&gt;result&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;server:&lt;span class="w"&gt; &lt;/span&gt;INSERT&lt;span class="w"&gt; &lt;/span&gt;ok
INSERT&lt;span class="w"&gt; &lt;/span&gt;ok
&lt;span class="nv"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;name,&lt;span class="w"&gt; &lt;/span&gt;age&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;name&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;age&lt;span class="w"&gt; &lt;/span&gt;
---------+-----
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;garry&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ted&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And against a follower (note the different port):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;psql&lt;span class="w"&gt; &lt;/span&gt;-h&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;127&lt;/span&gt;.0.0.1&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6001&lt;/span&gt;
psql&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;.4,&lt;span class="w"&gt; &lt;/span&gt;server&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.0.0&lt;span class="o"&gt;)&lt;/span&gt;
Type&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;help.

&lt;span class="nv"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;age,&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;age&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;name
-----+---------
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ted&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;garry&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All code for this post is &lt;a href="https://github.com/eatonphil/waterbugdb"&gt;available on Github in the fondly named
WaterbugDB repo&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="plan-of-attack"&gt;Plan of attack&lt;/h3&gt;&lt;p&gt;Influenced by &lt;a href="https://youtu.be/rqO9PtBkiSQ?t=2332"&gt;Philip O'Toole's talk on rqlite at Hacker
Nights&lt;/a&gt; we'll
have a Postgres wire protocol server in front. As it receives queries
it will respond immediately to &lt;code&gt;SELECT&lt;/code&gt;s. Otherwise for &lt;code&gt;CREATE TABLE&lt;/code&gt;s
and &lt;code&gt;INSERT&lt;/code&gt;s it will send the entire query string to the Raft
cluster. Each process that is part of the Raft cluster will implement
the appropriate functions for handling Raft messages. In this case the
messages will just be to create a table or insert data.&lt;/p&gt;
&lt;p&gt;So every running process will run a Postgres wire protocol server, a
Raft server, and an HTTP server that you'll see is an implementation
detail about how processes join to the same Raft cluster.&lt;/p&gt;
&lt;p&gt;Every running process will have its own directory for storing data.&lt;/p&gt;
&lt;h3 id="raft"&gt;Raft&lt;/h3&gt;&lt;p&gt;There is likely a difference between Raft, the paper, and Raft, the
implementations. When I refer to Raft in the rest of this post I'm
going to be referring to an implementation.&lt;/p&gt;
&lt;p&gt;And although CockroachDB use's &lt;a href="https://github.com/etcd-io/etcd"&gt;etcd's Raft
implementation&lt;/a&gt;, I didn't realize
that when I started building this project. I used &lt;a href="https://pkg.go.dev/github.com/hashicorp/raft"&gt;Hashicorp's Raft
implementation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Raft allows us to reliably keep multiple nodes in sync with a log of
messages. Each node in the Raft cluster implements a finite state
machine (FSM) with three operations: apply, snapshot, and restore. Our
finite state machine will embed a postgres engine we'll build out
after this to handle query execution.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bytes&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;io&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;net&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;strings&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;time&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/google/uuid&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/hashicorp/raft&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/hashicorp/raft-boltdb&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/jackc/pgproto3/v2&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pgquery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/pganalyze/pg_query_go/v2&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;go.etcd.io/bbolt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgFsm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From what I understand, the snapshot operation allows Raft to truncate
logs. It is used in conjuction with restoring. On startup if there is
a snapshot, restore is called so you can load the snapshot. Then
afterwards all logs not yet snapshotted are replayed through the apply
operation.&lt;/p&gt;
&lt;p&gt;To keep this implementation simple we'll just fail all snapshots so
restore will never be called and all logs will be replayed every time
on startup through the apply operation. This is of course inefficient
but it keeps the code simpler.&lt;/p&gt;
&lt;p&gt;When we write the startup code we'll need to delete the database so
that these apply calls happen fresh.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshotNoop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshotNoop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SnapshotSink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshotNoop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgFsm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FSMSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshotNoop&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgFsm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Restore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReadCloser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Nothing to restore&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, applying is receiving a single message and applying it for the
node. In this project the message will be a &lt;code&gt;CREATE TABLE&lt;/code&gt; or &lt;code&gt;INSERT&lt;/code&gt;
query. So we'll parse the query and pass it to the postgres engine for
execution.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgFsm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LogCommand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgquery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not parse payload: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown raft log type: %#v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Panic-ing here is actually the &lt;a href="https://github.com/hashicorp/raft/issues/307"&gt;advised
behavior&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="raft-server"&gt;Raft server&lt;/h4&gt;&lt;p&gt;Now we can set up the actual Raft server and pass an instance of this
FSM. This is a bunch of boilerplate that would matter in production
installs but for us basically we just need to tell Raft where to run
and how to store its own internal data, including its all-important
message log.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setupRaft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raftAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgFsm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Raft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MkdirAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ModePerm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raftboltdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewBoltStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bolt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create bolt store: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;snapshots&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewFileSnapshotStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;snapshot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create snapshot store: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tcpAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResolveTCPAddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tcp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raftAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not resolve address: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewTCPTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raftAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tcpAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create tcp transport: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;raftCfg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DefaultConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;raftCfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LocalID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServerID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewRaft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raftCfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snapshots&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create raft instance: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Cluster consists of unjoined leaders. Picking a leader and&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// creating a real cluster is done manually after startup.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BootstrapCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Servers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServerID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LocalAddr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Every instance of this process will run this and will start off as a
leader in a new cluster. We'll expose an HTTP server that allows a
leader to talk to other leaders to tell them to stop leading and
follow it. This HTTP endpoint in the HTTP server is how we'll get from
N process with N leaders and N clusters to N processes with 1 leader
and 1 cluster.&lt;/p&gt;
&lt;p&gt;That's basically it for the core Raft bits. So let's build out that
HTTP server and follow endpoint.&lt;/p&gt;
&lt;h3 id="http-follow-endpoint"&gt;HTTP follow endpoint&lt;/h3&gt;&lt;p&gt;Our HTTP server will have just one endpoint that tells the process (a)
to contact another process (b) so that process (b) joins the process
(a) cluster.&lt;/p&gt;
&lt;p&gt;The HTTP server will need to have the process (a)'s Raft instance
to be able to start this join action. And in order for Raft to know
how to contact the process (b) we'll need to tell it both the
process (b)'s unique Raft node id (we'll give it a unique id ourselves
when we start the process) and the process (b)'s Raft server port.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Raft&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;addFollowerHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;followerId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;followerAddr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;addr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Leader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;`json:&amp;quot;error&amp;quot;`&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Not the leader&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AddVoter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServerID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;followerId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServerAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;followerAddr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to add follower: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it! Let's move on to the query engine.&lt;/p&gt;
&lt;h3 id="query-engine"&gt;Query engine&lt;/h3&gt;&lt;p&gt;The query engine is a wrapper around a storage layer. We'll bring in
&lt;a href="https://github.com/etcd-io/bbolt"&gt;bbolt&lt;/a&gt;.&lt;/p&gt;
&lt;p class="note"&gt;
  I originally built this
  with &lt;a href="https://github.com/cockroachdb/pebble"&gt;Cockroach's pebble&lt;/a&gt; but pebble has a
  &lt;a href="https://app.bountysource.com/issues/99017984-unable-to-build-xxhash-conflicts-with-other-package"&gt;transitive dependency on a C library that has function names that
    conflict with function names in the C library that pg_query_go
    wraps&lt;/a&gt;.
&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newPgEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  bbolt organizes data into buckets. Buckets might be a natural way to
  store table rows (one bucket per table) but to keep the implementation
  simple we'll put all table metadata and row data into a single `data`
  bucket.
&lt;/p&gt;&lt;p&gt;The entrypoint we called in the Raft apply implementation above was
&lt;code&gt;execute&lt;/code&gt;. It took a parsed list of statements. We'll iterate over the
statements, figuring out the kind of each statement, and call out to a
dedicated helper for each kind.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgquery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ParseResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetStmts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetStmt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetCreateStmt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;executeCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetInsertStmt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;executeInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetSelectStmt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;executeSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown statement type: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  The pg_query_go docs are not super helpful. I had to build a
  &lt;a href="https://github.com/eatonphil/waterbugdb/blob/main/astexplorer/main.go"&gt;separate
  AST explorer program&lt;/a&gt; to make it easier to understand this parser.
&lt;/p&gt;&lt;p&gt;Let's start with creating a table.&lt;/p&gt;
&lt;h3 id="create-table"&gt;Create table&lt;/h3&gt;&lt;p&gt;When a table is created, we'll need to store its metadata.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tableDefinition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ColumnNames&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ColumnTypes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First we pull that metadata out of the AST.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;executeCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgquery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CreateStmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tableDefinition&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Relation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Relname&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TableElts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetColumnDef&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ColumnNames&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ColumnNames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Colname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Names is namespaced. So `INT` is pg_catalog.int4. `BIGINT` is pg_catalog.int8.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;columnType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TypeName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Names&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;columnType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;columnType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;columnType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetString_&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Str&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ColumnTypes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ColumnTypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;columnType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we need to store this in the storage layer. The easiest/dumbest
way to do this is to serialize the metadata to JSON and store it with
key: &lt;code&gt;tables_${tableName}&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tableBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not marshal table: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CreateBucketIfNotExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tables_&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tableBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not set key-value: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we'll build a helper to reverse that operation, pulling out table
metadata from the storage layer by the table name:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getTableDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;tableDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tableDefinition&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Table does not exist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;valBytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tables_&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not unmarshal table: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it for our basic &lt;code&gt;CREATE TABLE&lt;/code&gt; support! Let's do &lt;code&gt;INSERT&lt;/code&gt; next.&lt;/p&gt;
&lt;h3 id="insert-row"&gt;Insert row&lt;/h3&gt;&lt;p&gt;Our support for insert will only support literal/constant &lt;code&gt;VALUES&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;executeInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgquery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InsertStmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tblName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Relation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Relname&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;slct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetSelectStmt&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;GetSelectStmt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;slct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ValuesLists&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rowData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetList&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Items&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetAConst&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetString_&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;rowData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetInteger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;rowData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ival&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown value type: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It would be better to abstract this &lt;code&gt;VALUES&lt;/code&gt; code into a helper so it
could be used by &lt;code&gt;SELECT&lt;/code&gt;s too but out of laziness we'll just keep
this here.&lt;/p&gt;
&lt;p&gt;Next we need to write the row to the storage layer. We'll serialize
the row data to JSON (inefficient because we know the row structure,
but JSON is easy). We'll store the row with a prefix including the
table name and we'll give its key a unique UUID. When we're iterating
over rows in the table we'll be able to do a prefix scan that will
recover just the rows in this table.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;rowBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not marshal row: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CreateBucketIfNotExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rows_&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;tblName&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rowBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not store row: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally we can move on to support &lt;code&gt;SELECT&lt;/code&gt;!&lt;/p&gt;
&lt;h3 id="select-rows"&gt;Select rows&lt;/h3&gt;&lt;p&gt;Unlike &lt;code&gt;CREATE TABLE&lt;/code&gt; and &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;SELECT&lt;/code&gt; will need to return rows,
column names, and because the Postgres wire protocol wants it, column
types.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fieldNames&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fieldTypes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First we pull out the table name and the fields selected, looking up
field types in the table metadata.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;executeSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgquery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SelectStmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tblName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FromClause&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;GetRangeVar&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Relname&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTableDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tblName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgResult&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TargetList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fieldName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetResTarget&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetColumnRef&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;GetString_&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Str&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldNames&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldNames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fieldName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fieldType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ColumnNames&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fieldName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fieldType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ColumnTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fieldType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown field: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fieldName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldTypes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldTypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fieldType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we do a prefix scan to grab all rows in the table from the
storage layer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rows_&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tblName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HasPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unable to unmarshal row: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;targetRow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldNames&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tbl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ColumnNames&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;targetRow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetRow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;targetRow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it for &lt;code&gt;SELECT&lt;/code&gt;! The last function we'll implement is a
helper for deleting all data in the storage layer. This will be called
on startup before Raft logs are applied so the database always ends up
in a consistent state.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bolt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;bkt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bkt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeleteBucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we're ready to move on to the final layer, the Postgres wire
protocol.&lt;/p&gt;
&lt;h3 id="postgres-wire-protocol-server"&gt;Postgres wire protocol server&lt;/h3&gt;&lt;p&gt;&lt;a href="https://github.com/jackc/pgproto3"&gt;jackc/pgproto3&lt;/a&gt; is an
implementation of the Postgres wire protocol for Go. It allows us to
implement a server that can respond to requests by Postgres clients
like &lt;code&gt;psql&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It works by wrapping a TCP connection. So we'll start by building a
function that does the TCP serving loop.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;runPgServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Raft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ln&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tcp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;localhost:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgConn&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;pgConn&lt;/code&gt; instance needs access to the database directly so it can
respond to &lt;code&gt;SELECT&lt;/code&gt;s. And it needs the Raft instance for all other
queries.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgConn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Conn&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;raft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Raft&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;handle&lt;/code&gt; function we called above will grab the current message
via the pgproto3 package and handle startup messages and regular
messages.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pgc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewBackend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewChunkReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleStartupMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pgc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pgc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Startup messages include authorization and SSL checks. We'll allow
anything in the former and respond "no" to the latter.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handleStartupMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pgconn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Backend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;startupMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgconn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReceiveStartupMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error receiving startup message: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;startupMessage&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartupMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AuthenticationOk&lt;/span&gt;&lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReadyForQuery&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;TxStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'I'&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error sending ready for query: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SSLRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;N&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error sending deny SSL request: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleStartupMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pgconn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown startup message: %#v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;startupMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Within the main &lt;code&gt;handleMessage&lt;/code&gt; logic we'll check the type of message.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handleMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pgc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Backend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Receive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error receiving message: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// TODO&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Terminate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Received message other than Query from client: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If the message is a query we'll parse it and respond immediately to &lt;code&gt;SELECT&lt;/code&gt;s.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;stmts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgquery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error parsing query: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stmts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetStmts&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Only make one request at a time.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetStmts&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Handle SELECTs here&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetStmt&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;GetSelectStmt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newPgEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;executeSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writePgResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(We'll implement that &lt;code&gt;writePgResult&lt;/code&gt; helper shortly below.) Otherwise
we'll add the query to the Raft log and return a basic response.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Otherwise it's DDL/DML, raftify&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;future&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Apply&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not apply: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not apply (internal): %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; ok&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Terminate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Received message other than Query from client: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;done&lt;/code&gt; is an important helper that tells the Postgres connection that
the query is complete and the server is ready to receive another
query. Without this response &lt;code&gt;psql&lt;/code&gt; just hangs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CommandComplete&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;CommandTag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)}).&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReadyForQuery&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;TxStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'I'&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to write query response: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now let's implement the &lt;code&gt;writePgResult&lt;/code&gt; helper. This function
needs to translate from our &lt;code&gt;pgResult&lt;/code&gt; struct to the format require by
pgproto3.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dataTypeOIDMap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pg_catalog.int4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;writePgResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pgResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RowDescription&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldNames&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FieldDescription&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;DataTypeOID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dataTypeOIDMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fieldTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;dr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgproto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DataRow&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Failed to marshal cell: %s\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;dr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SELECT %d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we're done with everything but &lt;code&gt;func main()&lt;/code&gt;!&lt;/p&gt;
&lt;h3 id="main"&gt;Main&lt;/h3&gt;&lt;p&gt;On startup, each process must be assigned (by the parent process) a
unique node id (any unique string is ok) and ports for the Raft
server, Postgres server, and HTTP server. We'll build a short
&lt;code&gt;getConfig&lt;/code&gt; helper to grab these from arguments.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;httpPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;raftPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pgPort&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--node-id&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--http-port&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--raft-port&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raftPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--pg-port&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pgPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Missing required parameter: --node-id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raftPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Missing required parameter: --raft-port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Missing required parameter: --http-port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pgPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Missing required parameter: --pg-port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now in &lt;code&gt;main&lt;/code&gt; we'll grab the config and set up this process's
database. All processes will put their data in a top-level &lt;code&gt;data&lt;/code&gt;
directory to make managing the directories easier. But within that
directory each process will have their own unique directories for data
storage based on the unique node id.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dataDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MkdirAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ModePerm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not create data directory: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bolt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/data&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mo"&gt;0600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not open bolt db: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to clean up the database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newPgEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Start off in clean state&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Set up the Raft server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pgFsm&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pe&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setupRaft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;raft&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;localhost:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raftPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Set up the HTTP server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/add-follower&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addFollowerHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And finally, kick off the Postgres server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;runPgServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pgPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally. Finally. Finally done. Let's give it a go. :)&lt;/p&gt;
&lt;h3 id="what-hath-god-wrought"&gt;What hath god wrought&lt;/h3&gt;&lt;p&gt;First, initialize the go module and then build the app.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;mod&lt;span class="w"&gt; &lt;/span&gt;init&lt;span class="w"&gt; &lt;/span&gt;waterbugdb
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;mod&lt;span class="w"&gt; &lt;/span&gt;tidy
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now in terminal 1 start an instance of the database,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./waterbugdb&lt;span class="w"&gt; &lt;/span&gt;--node-id&lt;span class="w"&gt; &lt;/span&gt;node1&lt;span class="w"&gt; &lt;/span&gt;--raft-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2222&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--http-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8222&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--pg-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6000&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then in terminal 2 start another instance.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;./waterbugdb&lt;span class="w"&gt; &lt;/span&gt;--node-id&lt;span class="w"&gt; &lt;/span&gt;node2&lt;span class="w"&gt; &lt;/span&gt;--raft-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2223&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--http-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8223&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--pg-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6001&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And in terminal 3, tell &lt;code&gt;node1&lt;/code&gt; to have &lt;code&gt;node2&lt;/code&gt; follow it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'localhost:8222/add-follower?addr=localhost:2223&amp;amp;id=node2'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then open &lt;code&gt;psql&lt;/code&gt; against port &lt;code&gt;6000&lt;/code&gt;, the leader.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;psql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6000&lt;/span&gt;
&lt;span class="n"&gt;psql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6000&lt;/span&gt;
&lt;span class="n"&gt;psql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="n"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'garry'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'ted'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;could&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interpret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="n"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="c1"&gt;---------+-----&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;garry&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;ted&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now kill &lt;code&gt;node1&lt;/code&gt; in terminal 1. Then start it up again. &lt;code&gt;node2&lt;/code&gt; will
now be the leader. So exit &lt;code&gt;psql&lt;/code&gt; in terminal 3 and enter it again
pointed at &lt;code&gt;node2&lt;/code&gt;, port &lt;code&gt;6001&lt;/code&gt;. Add new data.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;psql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6001&lt;/span&gt;
&lt;span class="n"&gt;psql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'ava'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'ming'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;could&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interpret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="n"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="c1"&gt;-----+---------&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;ted&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;garry&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;ming&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;ava&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Exit &lt;code&gt;psql&lt;/code&gt; in terminal 3 and start it up again against &lt;code&gt;node1&lt;/code&gt; again,
port &lt;code&gt;6000&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;psql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6000&lt;/span&gt;
&lt;span class="n"&gt;psql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;phil&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="c1"&gt;-----+---------&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;ted&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;garry&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;ming&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;ava&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nifty stuff.&lt;/p&gt;
&lt;h3 id="summary"&gt;Summary&lt;/h3&gt;&lt;p&gt;So on the one hand this was a more complex post than my usual. Each
process needed three servers running. Two of those servers we managed
directly and the Raft server was managed by the Raft library.&lt;/p&gt;
&lt;p&gt;On the other hand, we did this all in a really small amount of
code. Yes many edge cases were unhandled and massive amount of SQL was
unhandled. And yes there are tons of inefficiencies like using JSON,
an unstructured format when every table has fixed structure. But
hopefully now you have an idea of how a project like this &lt;em&gt;could be
structured&lt;/em&gt;. And there's the beginnings of a framework for filling in
syntax/edge cases over time.&lt;/p&gt;
&lt;p&gt;Additionally, the only problem we solved with consensus was
replication, not sharding. This, and it's more complicated cousin
(cross-shard transactions), is truly the special sauce Cockroach
brings.&lt;/p&gt;
&lt;p&gt;Read more about building an intuition for sharding, replication, and
distributed consensus
[here](&lt;a href="https://notes.eatonphil.com/2024-02-08-an-intuition-for-distributed-consensus-in-oltp-systems.html"&gt;https://notes.eatonphil.com/2024-02-08-an-intuition-for-distributed-consensus-in-oltp-systems.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;New blog post is up :) Let's build a distributed postgres proof of concept.&lt;a href="https://t.co/Z8BDzF1bUw"&gt;https://t.co/Z8BDzF1bUw&lt;/a&gt; &lt;a href="https://t.co/aSkOjr9Yrh"&gt;pic.twitter.com/aSkOjr9Yrh&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1526598365634605058?ref_src=twsrc%5Etfw"&gt;May 17, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Tue, 17 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/distributed-postgres.html</guid></item><item><title>The Law of Conservation of Risk</title><link>https://www.swyx.io/risk-conservation</link><description>&lt;p&gt;Risk cannot be created or destroyed, it can only be redistributed&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Mon, 16 May 2022 05:15:58 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/risk-conservation</guid></item><item><title>Python tip 3: expression and result with f-string</title><link>https://learnbyexample.github.io/tips/python-tip-3/</link><description>&lt;p&gt;In case you haven't yet discovered this awesome &lt;strong&gt;f-string&lt;/strong&gt; feature, you can add &lt;code&gt;=&lt;/code&gt; after an expression to get both the expression and the result in the output.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;num1 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;num2 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;7
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{num1 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;+ &lt;/span&gt;&lt;span&gt;num2 = }&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'num1 + num2 = 49'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{num1 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;+ &lt;/span&gt;&lt;span&gt;(num2 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;* &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10&lt;/span&gt;&lt;span&gt;) = }&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'num1 + (num2 * 10) = 112'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use it often to quickly test a function:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="background-color: #562d56bf; color: #f8f8f8;"&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style="color: #5597d6;"&gt;isodd&lt;/span&gt;&lt;span&gt;(n):
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;return &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;bool&lt;/span&gt;&lt;span&gt;(n &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;% &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;isodd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42&lt;/span&gt;&lt;span&gt;) = }&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;isodd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;42&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;False
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;f&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;isodd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;123&lt;/span&gt;&lt;span&gt;) = }&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;isodd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;123&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://docs.python.org/3/library/string.html#formatstrings"&gt;docs.python: Format String Syntax&lt;/a&gt;, &lt;a href="https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals"&gt;docs.python: Formatted string literals&lt;/a&gt; and &lt;a href="https://fstring.help/"&gt;fstring.help&lt;/a&gt; for documentation and examples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook for a short, introductory guide for the Python programming language.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Mon, 16 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-3/</guid></item><item><title>Python tip 2: membership operator</title><link>https://learnbyexample.github.io/tips/python-tip-2/</link><description>&lt;p&gt;The &lt;code&gt;in&lt;/code&gt; membership operator checks if a given value is part of a collection of values. Here's an example with &lt;code&gt;range()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;num &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# checks if num is present among the integers 3 or 4 or 5
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;num &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of a series of &lt;code&gt;==&lt;/code&gt; comparisons combined with the &lt;code&gt;or&lt;/code&gt; boolean operator, you can utilize the &lt;code&gt;in&lt;/code&gt; operator.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;pet &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cat'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# instead of doing this
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;pet &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;== &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bat' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;or &lt;/span&gt;&lt;span&gt;pet &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;== &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cat' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;or &lt;/span&gt;&lt;span&gt;pet &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;== &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'dog'
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# use the membership operator
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;pet &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bat'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cat'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'dog'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When applied to strings, the &lt;code&gt;in&lt;/code&gt; operator performs substring comparison.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;fruit &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'mango'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'an' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;fruit
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'at' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;fruit
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;False
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To invert the membership test, use the &lt;code&gt;not in&lt;/code&gt; operator.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;pet &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'parrot'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;pet &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bat'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cat'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'dog'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;False
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;pet &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;not in &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bat'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'cat'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'dog'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://docs.python.org/3/reference/expressions.html#membership-test-operations"&gt;docs.python: Membership test operations&lt;/a&gt; for documentation. See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Mon, 16 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-2/</guid></item><item><title>Debug woes 3: matching uppercase letters</title><link>https://learnbyexample.github.io/mini/debug-woes-3/</link><description>&lt;p&gt;So, I was going through &lt;a href="https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion"&gt;GNU bash manual: Shell Parameter Expansion&lt;/a&gt; and trying out examples to check if I was understanding the features well.&lt;/p&gt;
&lt;p&gt;When it came to case conversion, it was a bit confusing to know that you can only use a single character length glob. Here are the examples for lowercase to uppercase conversion that I used:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ fruit=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'apple'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# all characters to uppercase
&lt;/span&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;${fruit^^}&amp;quot;
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;APPLE
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# convert any character that matches [g-z] to uppercase
&lt;/span&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;${fruit^^[g-z]}&amp;quot;
&lt;/span&gt;&lt;span&gt;aPPLe
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# this won't work since 'sky-' is not a single character
&lt;/span&gt;&lt;span&gt;$ c=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'sky-rose'
&lt;/span&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;${c^^*-}&amp;quot;
&lt;/span&gt;&lt;span&gt;sky&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;rose
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To convert uppercase to lowercase, you just need to use &lt;code&gt;,&lt;/code&gt; instead of &lt;code&gt;^&lt;/code&gt;. Sounds simple right? It really is. But, I got stuck while trying to modify the above examples:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ fruit=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'APPLE'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# worked as expected
&lt;/span&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;${fruit,,}&amp;quot;
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# expected 'ApplE' but got 'APPLE'
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# can you spot the mistake?
&lt;/span&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;${fruit,,[g-z]}&amp;quot;
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;APPLE
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I usually go through documentation and stackexchange sites when I'm stuck. After going through some threads, I came across &lt;a href="https://unix.stackexchange.com/q/500274/109046"&gt;this unix.stackexchange&lt;/a&gt; example:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ str=&lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;HELLO&amp;quot;
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #aeb52b;"&gt;%s&lt;/span&gt;&lt;span style="color: #d07711;"&gt;\n' &amp;quot;${str,,[HEO]}&amp;quot;
&lt;/span&gt;&lt;span&gt;heLLo
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, I thought, this seems similar to what I wanted. Need to check out if this works on my machine. Before I even finished typing the example, my brain's light bulb turned on. I should have used &lt;code&gt;G-Z&lt;/code&gt; instead of lowercase range.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ echo &lt;/span&gt;&lt;span style="color: #d07711;"&gt;&amp;quot;${fruit,,[G-Z]}&amp;quot;
&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;ApplE
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><author>learnbyexample</author><pubDate>Fri, 13 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/mini/debug-woes-3/</guid></item><item><title>CLI tip 10: version sort</title><link>https://learnbyexample.github.io/tips/cli-tip-10/</link><description>&lt;p&gt;You can use &lt;code&gt;sort -V&lt;/code&gt; for sorting numerical input that is mixed with other characters. It also helps when you want to treat digits after a decimal point as whole numbers, for example if &lt;code&gt;1.10&lt;/code&gt; should be greater than &lt;code&gt;1.2&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'1.5\n1.10\n1.2' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; sort &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;n
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.10
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.2
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.5
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'1.5\n1.10\n1.2' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; sort &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;V
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.2
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.5
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1.10
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ cat versions.txt
&lt;/span&gt;&lt;span&gt;file2
&lt;/span&gt;&lt;span&gt;cmd5.&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2
&lt;/span&gt;&lt;span&gt;file10
&lt;/span&gt;&lt;span&gt;cmd1.&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6
&lt;/span&gt;&lt;span&gt;file5
&lt;/span&gt;&lt;span&gt;cmd5.&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;$ sort &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;V&lt;/span&gt;&lt;span&gt; versions.txt
&lt;/span&gt;&lt;span&gt;cmd1.&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6
&lt;/span&gt;&lt;span&gt;cmd5.&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2
&lt;/span&gt;&lt;span&gt;cmd5.&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;file2
&lt;/span&gt;&lt;span&gt;file5
&lt;/span&gt;&lt;span&gt;file10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's an example of dealing with numbers reported by the &lt;code&gt;time&lt;/code&gt; command (assuming all the entries have the same format).&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat timings.txt
&lt;/span&gt;&lt;span&gt;5m35.363s
&lt;/span&gt;&lt;span&gt;3m20.058s
&lt;/span&gt;&lt;span&gt;4m11.130s
&lt;/span&gt;&lt;span&gt;3m42.833s
&lt;/span&gt;&lt;span&gt;4m3.083s
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;$ sort &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;V&lt;/span&gt;&lt;span&gt; timings.txt
&lt;/span&gt;&lt;span&gt;3m20.058s
&lt;/span&gt;&lt;span&gt;3m42.833s
&lt;/span&gt;&lt;span&gt;4m3.083s
&lt;/span&gt;&lt;span&gt;4m11.130s
&lt;/span&gt;&lt;span&gt;5m35.363s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://www.gnu.org/software/coreutils/manual/html_node/Version-sort-overview.html"&gt;GNU coreutils manual: Version sort ordering&lt;/a&gt; for more details. Also, note that the &lt;code&gt;ls&lt;/code&gt; command uses lowercase &lt;code&gt;-v&lt;/code&gt; for this task.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://learnbyexample.github.io/cli_text_processing_coreutils/sort.html"&gt;sort command&lt;/a&gt; chapter from my &lt;a href="https://github.com/learnbyexample/cli_text_processing_coreutils"&gt;Command line text processing with GNU Coreutils&lt;/a&gt; ebook for more details.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 13 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-10/</guid></item><item><title>Regexp gotcha 1: grouping common portions</title><link>https://learnbyexample.github.io/mini/regexp-gotcha-1/</link><description>&lt;p&gt;Similar to &lt;code&gt;a(b+c)d = abd+acd&lt;/code&gt; in maths, you get &lt;code&gt;a(b|c)d = abd|acd&lt;/code&gt; in regular expressions. However, you'll have to be careful if quantifiers are involved.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;(a*|b*)&lt;/code&gt; isn't the same as &lt;code&gt;(a|b)*&lt;/code&gt;. Can you reason out why? Here's a railroad diagram to help you out:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Regexp grouping with quantifiers gotcha" src="/images/mini/regexp_gotcha_1.png" /&gt;&lt;/p&gt;
&lt;p align="center"&gt;Credit: &lt;a href="https://www.debuggex.com/"&gt;debuggex.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The difference is that &lt;code&gt;(a*|b*)&lt;/code&gt; only matches same letter sequences like &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;bb&lt;/code&gt;, &lt;code&gt;aaaaaa&lt;/code&gt;, etc. But &lt;code&gt;(a|b)*&lt;/code&gt; can match mixed sequences like &lt;code&gt;ababbba&lt;/code&gt; too. You can also simplify &lt;code&gt;(a|b)*&lt;/code&gt; to &lt;code&gt;[ab]*&lt;/code&gt; since it is just single character alternation in this particular example.&lt;/p&gt;
&lt;p&gt;Here's an illustration using Python:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; import &lt;/span&gt;&lt;span&gt;re
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;test &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'aa'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'abbaba'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'aaabbb'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bbbbb'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'abc'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;[s &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for &lt;/span&gt;&lt;span&gt;s &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;test &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;if &lt;/span&gt;&lt;span&gt;re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;fullmatch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;(a&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*|&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;b&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;)&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, s)]
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'aa'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bbbbb'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;[s &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for &lt;/span&gt;&lt;span&gt;s &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;test &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;if &lt;/span&gt;&lt;span&gt;re.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;fullmatch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #668f14;"&gt;r&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;(a&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span style="color: #7c8f4c;"&gt;b)&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'&lt;/span&gt;&lt;span&gt;, s)]
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'aa'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'abbaba'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'aaabbb'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'bbbbb'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Want to learn regular expressions from the basics with plenty of examples and exercises? I've written &lt;a href="https://learnbyexample.github.io/books"&gt;regexp ebooks for Python, JavaScript, Ruby and CLI tools&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 13 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/mini/regexp-gotcha-1/</guid></item><item><title>SQLite in Go, with and without cgo</title><link>http://notes.eatonphil.com/sqlite-in-go-with-and-without-cgo.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-05-12-sqlite-in-go-with-and-without-cgo.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Thu, 12 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/sqlite-in-go-with-and-without-cgo.html</guid></item><item><title>Building a toy Python @dataclass decorator</title><link>https://bytepawn.com/building-a-toy-python-dataclass-decorator.html</link><description>&lt;p&gt;I write a toy implementation of Python's &lt;code&gt;@dataclass&lt;/code&gt; decorator to improve my Python fu and learn more about decorators and metaprogramming.&lt;br /&gt;&lt;br /&gt;&lt;img alt="Python enum" src="/images/dataclasses.png" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Thu, 12 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/building-a-toy-python-dataclass-decorator.html</guid></item><item><title>Finished Shadowbringers</title><link>https://benovermyer.com/blog/2022/05/finished-shadowbringers/</link><description>&lt;p&gt;A few days ago I finished the content for Shadowbringers (the Final Fantasy XIV expansion). Now I'm working on the content that's between that and Endwalker.&lt;/p&gt;
&lt;p&gt;Well, that's the vague plan, but I'm also doing other types of content completely unrelated to the main story quest. Like fishing. I enjoy fishing in FFXIV, just like fishing was my primary activity in Animal Crossing when I still played that. I'm not sure why. I don't really like fishing in the real world - it squicks me out.&lt;/p&gt;
&lt;p&gt;Auto Pet Battle released a new expansion yesterday, so I'm playing that too. I'm starting to think I should try my hand at creating a single-player video game in the vein of Auto Pet Battle and Monster Train, where order and combos matter.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Wed, 11 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/05/finished-shadowbringers/</guid></item><item><title>Python tip 10: removeprefix and removesuffix string methods</title><link>https://learnbyexample.github.io/tips/python-tip-10/</link><description>&lt;p&gt;Python supports plenty of string methods that reduces the need for regular expressions. The &lt;code&gt;removeprefix()&lt;/code&gt; and &lt;code&gt;removesuffix()&lt;/code&gt; string methods were added in the Python 3.9 version. See &lt;a href="https://peps.python.org/pep-0616/"&gt;PEP 616&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;These methods help to delete an exact substring from the start and end of the input string respectively. Here are some examples:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #7f8989;"&gt;# remove 'sp' if it matches at the start of the input string
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'spare'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;removeprefix&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'sp'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'are'
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# 'par' is present in the input, but not at the start
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'spare'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;removeprefix&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'par'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'spare'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# remove 'me' if it matches at the end of the input string
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# only one occurrence of the match will be removed
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'this meme'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;removesuffix&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'me'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'this me'
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# characters have to be matched exactly in the same order
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'this meme'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;removesuffix&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'em'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'this meme'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These remove methods will delete the given substring only once from the start or end of the string. On the other hand, the strip methods treat the argument as a set of characters to be matched any number of times in any order until a non-matching character is found. Here are some examples:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'these memes'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;removesuffix&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'esm'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'these memes'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'these memes'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;rstrip&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'esm'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'these '
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'effective'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;removeprefix&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ef'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'fective'
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'effective'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;lstrip&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ef'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ctive'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 11 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-10/</guid></item><item><title>Seeing is understanding</title><link>https://blog.bayindirh.io/blog/seeing-is-understanding/</link><description>&lt;p&gt;This post builds upon "&lt;a href="https://blog.bayindirh.io/blog/i-decided-to-trust-cloud-storage/"&gt;I decided to trust cloud storage&lt;/a&gt;". If you didn't read it, please spare a few minutes for going through it for a better context.&lt;/p&gt;
&lt;p&gt;As I started to move my files to cloud, a lot has happened. I've decided on a single provider for my files, bought extended file revision membership on said provider, and more importantly, started to move my files over there. The backup plan is not completely realized yet, but progressing slowly. I know I'm late to the cloud party, but being able to access your files anywhere is life changing and nice.&lt;/p&gt;
&lt;p&gt;However, it is not all rainbows and unicorns.&lt;/p&gt;
&lt;p&gt;I can confidently say that extended file revision membership paid itself off. I use a couple of tools to interface with my cloud storage account. One of them is capable of "out of tree synchronization", which is a fancy name for synchronizing a folder on the cloud anywhere on your computer. This allows syncing large folders to secondary drives and accessing them without filing the primary drive. Due to a complex case of application miscommunication and user error, I deleted a folder containing over 40,000 files. However, the files were restorable and nothing is lost. Having a year for recovering files is assuring if something goes unnoticed. Lastly, the storage provider sends an email in the lines of "You deleted a lot of files. If you didn't do that intentionally, here's a list. You have a year to restore them", which is neat.&lt;/p&gt;
&lt;p&gt;Another revealing thing about cloud storage is the visibility it provides for your files. As a person who has a similar history to a nice internet stranger who &lt;a href="https://dsebastien.net/blog/2022-04-03-25-years-of-personal-knowledge-management"&gt;documented his 25+ year journey&lt;/a&gt;; I have a lot files, on a lot of drives, organized in a plethora of ways, over a very long time. When combined with the density of modern era storage mediums, a lot files can be stored in a deceptively small volume of space, making them real-world &lt;a href="https://www.dndbeyond.com/magic-items/4581-bag-of-holding"&gt;bags of holding&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previously, I have started to consolidate these drives to reduce the drive count, however, as it turned out, copying files and drinking tea while waiting for tasks to finish is a poor way for gauging the depth of the task at hand. Digging into these drives, moving the files to the cloud and organizing them was revealing.&lt;/p&gt;
&lt;p&gt;Much more revealing than I ever imagined, to be honest.&lt;/p&gt;
&lt;p&gt;In the era of multimedia, large files are the norm. A video recorded with a nice camcorder or a mirrorless camera can use gigabytes of space without much effort, and working with these files distorts your perception after a while. In reality, a great deal of information can be stored in small files. PDFs, text files, documents, and similar files can pack a lot of information into a minuscule space. Tucking these into a folder make them disappear. When opened for organization, the collection greets with all of its might.&lt;/p&gt;
&lt;p&gt;Then, I understood the height of the mountain I need to scale.&lt;/p&gt;
&lt;p&gt;As I move to the files to the cloud or put them aside to consider later, I started to grasp the size of accumulation happened over time, how I tucked things away with anticipation of returning back to them to handle them properly, but conned by the technology and by myself. Growing drives allowed hiding more into a smaller space, faster transfer speeds and more convenient interfaces allowed following the path of least resistance without thinking at all.&lt;/p&gt;
&lt;p&gt;However, when the day has come to organize all this accumulation and separate what matters from the cruft, all the debt has to be paid in full. It's possible to use the features which enabled all this accumulation for an advantage too. Advanced tools can find duplicates faster, bigger drives can give a bigger scratch space for organization, and faster interfaces &amp;amp; network can allow quicker transfer across drives or the planet.&lt;/p&gt;
&lt;p&gt;Now, the cloud storage has more folders and files than it ever has, but all the files are useful, meaningful and are the things I want to access. Seeing them reminds their existence, slows the accumulation and allows much greater reuse. The journey is in its opening legs, but it'll be much more fruitful than I ever anticipated. I can see that.&lt;/p&gt;
&lt;p&gt;Lastly, a 64 GB USB flash drive can carry a world, and then some. Keep that in mind.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Tue, 10 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/seeing-is-understanding/</guid></item><item><title>Python decorator patterns</title><link>https://bytepawn.com/python-decorator-patterns.html</link><description>&lt;p&gt;I show toy implementations of Python decorator patterns such as &lt;code&gt;@measure&lt;/code&gt;, &lt;code&gt;@repeat&lt;/code&gt;, &lt;code&gt;@trace&lt;/code&gt;, &lt;code&gt;@count&lt;/code&gt;, &lt;code&gt;@singleton&lt;/code&gt;, and &lt;code&gt;@app.route&lt;/code&gt; (made famous by Flask).&lt;br /&gt;&lt;br /&gt;&lt;img alt="Python enum" src="/images/decorators.jpg" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 08 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/python-decorator-patterns.html</guid></item><item><title>Talk Notes: Third Age of JavaScript - Three Years In</title><link>https://www.swyx.io/third-age-2022</link><description>&lt;p&gt;Slides and show notes for my updated Talk at Reactathon&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sat, 07 May 2022 20:25:45 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/third-age-2022</guid></item><item><title>I don't know how to build software</title><link>https://www.marginalia.nu/log/57-dont-know-how-to-build-software/</link><description>&lt;p&gt;There are a lot of ways of building software, there are many languages you could choose to build it with, many libraries to rely on, many frameworks to leverage, many architectural approaches, many platforms to choose, many paradigms of daily operations to follow.&lt;/p&gt;
&lt;p&gt;It takes years to get in-depth experience with just one permutation of these options.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been programming for over twenty years, only half the time professionally, but that is how long I&amp;rsquo;ve been building software. I&amp;rsquo;ve built about twelve applications in my twenty years of development, of varying size and complexity.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Fri, 06 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/57-dont-know-how-to-build-software/</guid></item><item><title>On minimalism and frugality</title><link>https://blog.bayindirh.io/blog/on-minimalism-and-frugality/</link><description>&lt;p&gt;For more background information about this post, and to see where I'm coming from, see previous post on this subject, &lt;a href="https://blog.bayindirh.io/blog/meditations-on-minimalism/"&gt;Meditations on minimalism&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As I ponder about minimalism, its advantages and what it brings to one's life; other promises start to show themselves. One of the biggest secondary promises is saving money.&lt;/p&gt;
&lt;p&gt;Saving money is a desirable action all in itself. It enables one to have a bigger buffer for darker days, allows greater freedom to try more things, or provide better opportunities for your youngsters while they're growing up. However, does being minimal automatically enable these things? I'm not sure.&lt;/p&gt;
&lt;p&gt;There is another mindset which is focused on saving money: Frugality. Its primary concern is saving money, and reducing influx of goods or expenditure of money is both the method and the target itself. This is where it contrasts with minimalism, which is concerned with reduction of goods, but not the expenditure itself directly. While frugality has a secondary promise of less belongings to deal with, this promise is a subject for another day.&lt;/p&gt;
&lt;p&gt;During my quest for reducing physical goods and minimizing the number of belongings, a pattern has emerged. I was replacing these physical goods with their digital equivalents. Books are replaced with ebooks, bulky storage devices are consolidated and &lt;a href="https://blog.bayindirh.io/blog/i-decided-to-trust-cloud-storage/"&gt;pushed to cloud&lt;/a&gt; with backup plans. This migration also required a couple of new software purchases and service subscriptions. As a result, this process is costing me both time and money.&lt;/p&gt;
&lt;p&gt;While the cost looks grim at first, there's an important catch. I'm saving future time by going through this migration and transformation. Reducing the number of computers, storage systems and services I use has a net positive effect on my free time and efficiency, even visible today. Normally, writing this blog wouldn't be possible if I was continuing my old ways of doing things.&lt;/p&gt;
&lt;p&gt;Today, I can say that frugality is not a given secondary effect of minimalism, at least in the initial stages of transformation. However, this subject needs further evaluation as the transformation progresses, things settle and new ways become the new norms. At that point, a logical next step may be another service level consolidation to eliminate unnecessary subscriptions. But, it's important to ensure that the elimination won't destabilize the established ways and shouldn't create a slippery slope towards extreme frugality, which affects one's quality of life for the sake of saving money.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Thu, 05 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/on-minimalism-and-frugality/</guid></item><item><title>Building a toy Python Enum class - Part II</title><link>https://bytepawn.com/building-a-simple-python-enum-class-part-ii.html</link><description>&lt;p&gt;I extend my previous toy implementation of Python's &lt;code&gt;Enum&lt;/code&gt; class to add more features.&lt;br /&gt;&lt;br /&gt;&lt;img alt="Python enum" src="/images/getattribute.png" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Thu, 05 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/building-a-simple-python-enum-class-part-ii.html</guid></item><item><title>Vim tip 8: join lines</title><link>https://learnbyexample.github.io/tips/vim-tip-8/</link><description>&lt;p&gt;In Normal mode, you can join lines using &lt;code&gt;J&lt;/code&gt; and &lt;code&gt;gJ&lt;/code&gt; commands. These differ in how the end-of-line character and indentation at the start of lines being joined are handled.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;J&lt;/kbd&gt; joins the current line and the next line
&lt;ul&gt;
&lt;li&gt;the deleted &lt;code&gt;&amp;lt;EOL&amp;gt;&lt;/code&gt; character is replaced with a space (unless there are trailing spaces or the next line starts with a &lt;code&gt;)&lt;/code&gt; character)&lt;/li&gt;
&lt;li&gt;indentation from the lines being joined are removed, &lt;em&gt;except the current line&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;3J&lt;/kbd&gt; joins the current line and next two lines with one space in between the lines&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;gJ&lt;/kbd&gt; joins the current line and the next line
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;EOL&amp;gt;&lt;/code&gt; character is deleted (space character won't be added)&lt;/li&gt;
&lt;li&gt;indentation won't be removed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; &lt;code&gt;joinspaces&lt;/code&gt;, &lt;code&gt;cpoptions&lt;/code&gt; and &lt;code&gt;formatoptions&lt;/code&gt; settings will affect the behavior of these commands. See &lt;a href="https://vimhelp.org/change.txt.html#J"&gt;:h J&lt;/a&gt; and scroll down for more details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 04 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-8/</guid></item><item><title>You (Probably) Shouldn't use a Lookup Table</title><link>https://specbranch.com/posts/lookup-tables/</link><description>&lt;p&gt;I have been working on another post recently, also related to division, but I wanted to address
a comment I got from several people on the previous division article.  This comment invariably
follows a lot of articles on using math to do things with &lt;code&gt;chars&lt;/code&gt; and &lt;code&gt;shorts&lt;/code&gt;.  It is: &amp;quot;why
are you doing all of this when you can just use a lookup table?&amp;quot;&lt;/p&gt;
&lt;p&gt;Even worse, a stubborn and clever commenter may show you a benchmark where your carefully-crafted
algorithm performs worse than their hamfisted lookup table.  Surely you have made a mistake and
you should just use a lookup table.  Just look at the benchmark!&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Wed, 04 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/lookup-tables/</guid></item><item><title>How the Democrats kicked out actual liberals</title><link>https://mikewarot.blogspot.com/2022/05/how-democrats-kicked-out-actual-liberals.html</link><description>&lt;p&gt;&amp;nbsp;Krystal Ball lays out exactly &lt;a href="https://www.youtube.com/watch?v=HCMox4dLz9s"&gt;how the Clintons sold out the liberal agenda.&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description><author>--Mike--</author><pubDate>Tue, 03 May 2022 03:29:51 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/05/how-democrats-kicked-out-actual-liberals.html</guid></item><item><title>CLI tip 1: remove metadata from images</title><link>https://learnbyexample.github.io/tips/cli-tip-1/</link><description>&lt;p&gt;Want to remove metadata (DateTime, Model, Orientation, ShutterSpeedValue, etc) from your images? You can use &lt;code&gt;mogrify&lt;/code&gt; or &lt;code&gt;convert&lt;/code&gt; tools provided by ImageMagick.&lt;/p&gt;
&lt;p&gt;GUI image viewer applications will usually allow you to see some of the image metadata. You can also use the &lt;code&gt;identify&lt;/code&gt; command line tool to get all the metadata:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# remove 'head' to get the entire list of metadata
&lt;/span&gt;&lt;span&gt;$ identify &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;verbose insect.jpg &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; grep &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'exif' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; head
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:ApertureValue: 113&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;32
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:ColorSpace: 1
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:ComponentsConfiguration: 1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;0
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:CompressedBitsPerPixel: 3&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:CustomRendered: 0
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:DateTime: 2016&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;12&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;03 11&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;26&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:DateTimeDigitized: 2016&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;12&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;03 11&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;26&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:DateTimeOriginal: 2016&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;12&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;03 11&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;26&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;:&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:DigitalZoomRatio: 4000&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;/&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4000
&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;exif:ExifOffset: 240
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's how you can remove such metadata from images:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# to create a new image with metadata removed
&lt;/span&gt;&lt;span&gt;$ convert &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;strip insect.jpg op.jpg
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# to modify the input image itself
&lt;/span&gt;&lt;span&gt;$ mogrify &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;strip insect.jpg
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also pass multiple images to &lt;code&gt;mogrify&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ mogrify &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;strip &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;*&lt;/span&gt;&lt;span&gt;.jpg
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Note that the image size after metadata removal may vary because of recompression.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;strong&gt;Further Reading&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://imagemagick.org/"&gt;ImageMagick&lt;/a&gt; — create, edit, compose, or convert digital images&lt;/li&gt;
&lt;li&gt;&lt;a href="https://askubuntu.com/questions/260810/how-can-i-read-and-remove-meta-exif-data-from-my-photos-using-the-command-line"&gt;How can I read and remove meta (exif) data from my photos using the command line?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unix.stackexchange.com/questions/312754/how-to-strip-metadata-from-image-files"&gt;How to strip metadata from image files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://softwareengineering.stackexchange.com/questions/42767/why-do-they-name-a-program-mogrify-in-imagemagick"&gt;What does mogrify mean?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Exif"&gt;wikipedia: Exif&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>learnbyexample</author><pubDate>Tue, 03 May 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-1/</guid></item><item><title>Building a toy Python Enum class - Part I</title><link>https://bytepawn.com/building-a-simple-python-enum-class.html</link><description>&lt;p&gt;I write a toy implementation of Python's &lt;code&gt;Enum&lt;/code&gt; class to learn about Python metaclasses.&lt;br /&gt;&lt;br /&gt;&lt;img alt="Python enum" src="/images/enum2.png" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Tue, 03 May 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/building-a-simple-python-enum-class.html</guid></item><item><title>Thoughts on writing</title><link>https://mikewarot.blogspot.com/2022/05/thoughts-on-writing.html</link><description>&lt;br /&gt;Nobody writes well written prose.&lt;br /&gt;&lt;br /&gt;Everyone writes, then does a better or worse job of editing. Like code, prose tends to crystalize into smaller and higher quality pieces over time.&lt;br /&gt;&lt;br /&gt;--- Process ---&lt;br /&gt;&lt;br /&gt;Write all of your thoughts in a stream of consciousness flow, don't worry about how it looks, just get your thoughts out of your head, and into the storage medium of your choice. This frees up stack space in your brain.&lt;br /&gt;&lt;br /&gt;Next - Iterate. Strategies you can use to help include:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Read it out loud to yourself. You'll immediately notice typos, grammatical and flow issues.&lt;/li&gt;&lt;li&gt;Walk away from it to gain some distance in time and space. When you come back you'll notice gaps or repetitions.&lt;/li&gt;&lt;/ul&gt;Repeat until you're happy.</description><author>--Mike--</author><pubDate>Tue, 03 May 2022 00:38:01 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/05/thoughts-on-writing.html</guid></item><item><title>QRP Labs QDX Rev 3 is here… all 2000 of them!</title><link>https://miscdotgeek.com/qrp-labs-qdx-rev-3-is-here-all-2000-of-them/</link><description>&lt;p&gt;Yep, get your wallet ready: The QDX Rev 3 is here. And there&amp;#8217;s more. There are shirts, a hat, a mug, and more. Check it out in the video below:&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://miscdotgeek.com/qrp-labs-qdx-rev-3-is-here-all-2000-of-them/" rel="noopener noreferrer" target="_self"&gt;QRP Labs QDX Rev 3 is here&amp;#8230; all 2000 of them!&lt;/a&gt; appeared first on &lt;a href="https://miscdotgeek.com" rel="noopener noreferrer" target="_self"&gt;MiscDotGeek&lt;/a&gt;.&lt;/p&gt;</description><author>MiscDotGeek</author><pubDate>Sun, 01 May 2022 11:28:23 GMT</pubDate><guid isPermaLink="true">https://miscdotgeek.com/qrp-labs-qdx-rev-3-is-here-all-2000-of-them/</guid></item><item><title>No Man's Sky</title><link>https://benovermyer.com/blog/2022/04/no-mans-sky/</link><description>&lt;p&gt;I've been playing a lot of No Man's Sky lately. It tends to go in waves - I'll play a lot of it for a short period of time, then I'll stop playing for months or even years. Then the cycle repeats.&lt;/p&gt;
&lt;p&gt;This time, I'm doing a lot more combat than I used to and not because I seek it out. The recent pirate expansion has increased the number and strength of pirate ships attacking me in space. The addition of a hotkey to automatically follow an enemy has made this a lot less annoying than before - combat is really easy in No Man's Sky, so having a feature to make it take less time is very welcome. Also, I had to do a quest chain that culminated in me fighting a very large army of Sentinels at one of my bases. That was harder, and I almost died a couple times trying to kill the swarm while also whittling away at very large mecha. That this was essentially a required quest in order to unlock certain (non-combat) features of my base was irritating, but eh, it was a one-time deal.&lt;/p&gt;
&lt;p&gt;With the help of the Internet, I discovered a couple tricks to getting resources. The first is that you can multiply your carbon pretty easily and make a ton of money off of it. You'll need a medium or large refiner, and a lot of oxygen. Then you just refine the carbon with the oxygen, and refine the result with the oxygen too, and just keep doing that until you have a ridiculous amount of carbon products. A quick way to get oxygen is to just buy it off of pilots in space station landing bays. The other trick is getting large quantities of other resources by equipping your ship with a positron ejector and then blasting the bejeesus out of the terrain at slow speed and low altitude. You'll get thousands of units of ferrite dust and other things this way.&lt;/p&gt;
&lt;p&gt;I discovered a perfect paradise planet. No inclement weather, no Sentinels, no hostile wildlife, a beautiful blue sky with two suns and a ringed planet off in the distance, and a generally lovely aesthetic. I named it Asgard, even if that's rather tired at this point. I'm working on building my largest base there now, though my primary base is still on a bit of a hellworld several star systems away.&lt;/p&gt;
&lt;p&gt;We'll see how long No Man's Sky keeps my interest. I'm still playing Final Fantasy XIV, and Galactic Civilizations IV launched a couple days ago, so that also has my attention.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Sat, 30 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/04/no-mans-sky/</guid></item><item><title>"Over 70% of all Porsche vehicles ever built are still on the road today"</title><link>https://bytepawn.com/porsche-70.html</link><description>&lt;p&gt;Porsche proudly advertises &lt;em&gt;"Over 70% of all Porsche vehicles ever built are still on the road today"&lt;/em&gt;. Is this a testament of the quality and longevity of Porsche cars, or simply a result of the brand switching from niche sportscar manufacturing to mass production around the year 1999?&lt;br /&gt;&lt;br /&gt; &lt;img alt="Over 70% of all Porsche vehicles ever built are still on the road today" src="/images/porsche-70.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 30 Apr 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/porsche-70.html</guid></item><item><title>Python tip 1: tuple argument for startswith/endswith methods</title><link>https://learnbyexample.github.io/tips/python-tip-1/</link><description>&lt;p&gt;You'd probably know about the &lt;code&gt;startswith()&lt;/code&gt; and &lt;code&gt;endswith()&lt;/code&gt; string methods.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'This is a sample string'
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;startswith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'This'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;startswith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'is'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;False
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;endswith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ing'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;True
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;sentence.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;endswith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'ly'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;False
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But did you know that you can also pass a &lt;code&gt;tuple&lt;/code&gt; of strings?&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;words &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'refuse'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'impossible'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'fire'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'present'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'read'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'shim'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;prefix &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'im'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'re'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'use'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;[w &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for &lt;/span&gt;&lt;span&gt;w &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;words &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;if &lt;/span&gt;&lt;span&gt;w.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;startswith&lt;/span&gt;&lt;span&gt;(prefix)]
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'refuse'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'impossible'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'read'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;[w &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;for &lt;/span&gt;&lt;span&gt;w &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;words &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;if &lt;/span&gt;&lt;span&gt;w.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;endswith&lt;/span&gt;&lt;span&gt;(prefix)]
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'refuse'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'fire'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'shim'&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Fri, 29 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-1/</guid></item><item><title>I decided to trust cloud storage</title><link>https://blog.bayindirh.io/blog/i-decided-to-trust-cloud-storage/</link><description>&lt;p&gt;For more background information and to read where I'm coming from, see my previous post, &lt;a href="https://blog.bayindirh.io/blog/meditations-on-minimalism/"&gt;meditations on minimalism&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm an old school person. For years, I always accomplished my things the old school way. Using a desktop system, preferring local-first file storage, organizing and curating these files by hand, sometimes painstakingly. This never meant that I denounce newer technologies, but I always put them to the back of the queue, or limited their use to the bare minimum. Over the years, this created a centralized file silo at home, with backups. I've built systems, and an ecosystem of applications to handle these files, their organization and other marginalia.&lt;/p&gt;
&lt;p&gt;Life was good.&lt;/p&gt;
&lt;p&gt;However, due to changing life circumstances, I have to change this storage system, for good. I won't have a place to put my silo for some unknown time, won't have the same time frame to organize it, and would need to access these files from more places to get things done.&lt;/p&gt;
&lt;p&gt;Enter, cloud storage.&lt;/p&gt;
&lt;p&gt;Cloud storage is nothing new, and I'm no stranger to it. To be honest, I'm using it for quite some time via Dropbox and Google Drive. While their support on the platform I prefer (Linux) is not first class, they're perfectly usable, and works reliably, at least. As a result, some of my files are living there, to enable mobility, collaboration and sharing. However, as I've said, the number of files living in these spaces were minimal.&lt;/p&gt;
&lt;p&gt;The reasons for this were numerous. First, trusting a remote server you don’t control with your files was hard. Then, having almost no bandwidth for uploading files made the service not practical. Lastly, but most importantly, I always had access to my silo, and the time to work there everyday.&lt;/p&gt;
&lt;p&gt;But, I missed the signs.&lt;/p&gt;
&lt;p&gt;First, I was using the tech already. I had accounts with two leading providers, and was paying one of them a good amount of money for ample storage and other features. Some merchants I was using were delivering my files there directly, automatically organizing them during the process.&lt;/p&gt;
&lt;p&gt;Second, the problems I mentioned was disappearing slowly. Mobile internet became affordable, and I was able to afford the top tier service. Home network was steadily becoming faster, incl. upload speeds. I was backing-up that space every day automatically, and never lost a file in any of these providers.&lt;/p&gt;
&lt;p&gt;Lastly, my workflows were integrating to these services. Some devices I got had their own cloud service, and many apps were seamlessly integrating over it. I started collaborating over cloud. Moreover, I was using these services more and more to integrate different systems and platforms, and make them work together.&lt;/p&gt;
&lt;p&gt;In short, I migrated to cloud without even knowing it, but still using my old ways hid that truth from myself.&lt;/p&gt;
&lt;p&gt;As a result, in the light of the recent changes in my life, I decided to move to and trust cloud even more extensively and knowingly, but with more robust backup procedures.&lt;/p&gt;
&lt;p&gt;At the same time, I realized that moving to a single place which can be accessed everywhere makes the data much more visible, easier to organize and pare down. This allows me to build systems around that storage system which automates other tasks, making  my life much easier.&lt;/p&gt;
&lt;p&gt;While the cloud is "someone else's computer", trusting that someone while being prepared brings many advantages, at first blush. I'll see how it feels as I integrate and use it more.&lt;/p&gt;
&lt;p&gt;Let's see what moving to cloud going to bring next.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Fri, 29 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/i-decided-to-trust-cloud-storage/</guid></item><item><title>Uncertain Future For Marginalia Search</title><link>https://www.marginalia.nu/log/56-uncertain-future/</link><description>&lt;p&gt;I found myself effectively without a job on short notice.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not at all worried about finding another one, I have savings, and I have experience, and I have demonstrable skill. What I am concerned about is finding a source of income that&amp;rsquo;s compatible with putting some time on my personal projects.&lt;/p&gt;
&lt;p&gt;Last bunch of years, I&amp;rsquo;ve been working 32 hour weeks, which is a pretty sweet deal especially combined with the zero hour commute you get working from home during the pandemic. Not every employer is fine with that, and while I do have options, I&amp;rsquo;m in a worse bargaining position than I have been before.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Thu, 28 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/56-uncertain-future/</guid></item><item><title>CLI tip 9: awk paragraph mode</title><link>https://learnbyexample.github.io/tips/cli-tip-9/</link><description>&lt;p&gt;&lt;code&gt;awk&lt;/code&gt; provides a handy shortcut to process input content paragraph wise. When &lt;code&gt;RS&lt;/code&gt; is set to empty string, one or more consecutive empty lines is used as the input record separator. Consider the below sample file:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ cat para.txt
&lt;/span&gt;&lt;span&gt;hi there
&lt;/span&gt;&lt;span&gt;how are you
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt; apples
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;12&lt;/span&gt;&lt;span&gt; bananas
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;blue sky
&lt;/span&gt;&lt;span&gt;yellow sun
&lt;/span&gt;&lt;span&gt;brown earth
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are some simple examples to filter paragraphs based on some criteria:&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# paragraphs containing 'sun'
&lt;/span&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;RS&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'/sun/'&lt;/span&gt;&lt;span&gt; para.txt
&lt;/span&gt;&lt;span&gt;blue sky
&lt;/span&gt;&lt;span&gt;yellow sun
&lt;/span&gt;&lt;span&gt;brown earth
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# paragraphs containing any digit character
&lt;/span&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;RS&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'/[0-9]/'&lt;/span&gt;&lt;span&gt; para.txt
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt; apples
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;12&lt;/span&gt;&lt;span&gt; bananas
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# print the first paragraph
&lt;/span&gt;&lt;span&gt;$ awk &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;-&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style="color: #c23f31;"&gt;RS&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'NR==1'&lt;/span&gt;&lt;span&gt; para.txt
&lt;/span&gt;&lt;span&gt;hi there
&lt;/span&gt;&lt;span&gt;how are you
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://learnbyexample.github.io/learn_gnuawk/record-separators.html#paragraph-mode"&gt;Paragraph mode section from my GNU awk ebook&lt;/a&gt; for more examples and corner cases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/learn_gnuawk"&gt;CLI text processing with GNU awk&lt;/a&gt; ebook if you are interested in learning about the &lt;code&gt;GNU awk&lt;/code&gt; command in more detail.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 27 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-9/</guid></item><item><title>HTML event handler attributes: down the rabbit hole</title><link>http://notes.eatonphil.com/event-handler-attributes.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-04-26-event-handler-attributes.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Tue, 26 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/event-handler-attributes.html</guid></item><item><title>"The company is all hot air"</title><link>https://bytepawn.com/the-company-is-all-hot-air.html</link><description>&lt;p&gt;Theranos, WeWork and the startup hustle.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Bayes vs z-test" src="/images/theranos-wework.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Tue, 26 Apr 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/the-company-is-all-hot-air.html</guid></item><item><title>Testing and Running Go API GW Lambda's Locally</title><link>https://boyter.org/posts/testing-running-api-gw-lambda-locally/</link><description>&lt;p&gt;I have been working with AWS API Gateway and Lambda using Go a lot recently. One of the more annoying things about API Gateway and Lambda is the inability to run things locally. As a result I tend to write a lot of unit tests to compensate. This works up till you start doing things like SQL queries as mocking away the database is a less than ideal situation if you are working with raw SQL, which I tend to do since I don&amp;rsquo;t like most ORM&amp;rsquo;s. These limitations of unit tests is why I prefer integration tests.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Mon, 25 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/testing-running-api-gw-lambda-locally/</guid></item><item><title>Upgrading the Iron Arachne planet generator</title><link>https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/</link><description>&lt;p&gt;Today I upgraded the graphics for the &lt;a href="https://ironarachne.com/#/planet" rel="external"&gt;planet generator on Iron Arachne&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was not a small task, as I taught myself how to do domain warping and rewrote most of the GLSL shaders
that are used to create these graphics.&lt;/p&gt;
&lt;p&gt;But first, the only one that did NOT get changed, because I like it as is:&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/gasgiant.png" /&gt;
&lt;p&gt;I might end up tweaking the gas giant a bit, but not today.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/arid.png" /&gt;
&lt;p&gt;The arid planet is a little more colorful, but still looks bleak. The new cloud shader is
a huge improvement.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/barren.png" /&gt;
&lt;p&gt;It's less obvious in this particular shot, but the barren planet gained a lot more detail
in its surface texture. I still don't care for how I did the vertex displacement, but eh, that can
wait for another day.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/garden.png" /&gt;
&lt;p&gt;The garden world was the hardest. I'm still not happy with it, but it's better than it was.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/jungle.png" /&gt;
&lt;p&gt;The jungle world looks much better. It definitely has more of a forested feel.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/ice.png" /&gt;
&lt;p&gt;The ice world is much more colorful than it used to be. Originally I was going to go for
a color scheme similar to the original, but I liked this version too much and kept it.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/ocean.png" /&gt;
&lt;p&gt;The ocean world now feels a lot less plastic and has more detail to it. The new clouds help.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/swamp.png" /&gt;
&lt;p&gt;The new swamp world looks just as unfriendly as the original, but perhaps more colorful now.
I might tone down the brighter hues in the future.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/toxic.png" /&gt;
&lt;p&gt;The toxic world is less cartoony now. It no longer has the neon green oceans and generally
looks like an awful place to visit.&lt;/p&gt;
&lt;img class="photo" src="https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/volcanic.png" /&gt;
&lt;p&gt;The new volcanic world is much more volcano-y. Instead of just oceans of lava, there are
now rivers too, and the glow is less pronounced.&lt;/p&gt;
&lt;p&gt;All in all, I think it's a pretty impressive upgrade, though there's still a lot of work
to be done. At some point I really want to figure out atmospheric scattering.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Fri, 22 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/04/upgrading-the-planet-generator/</guid></item><item><title>Meditations on minimalism</title><link>https://blog.bayindirh.io/blog/meditations-on-minimalism/</link><description>&lt;p&gt;I've been pondering about minimalism, and trying to implement it into my life for quite some time. However, the idea proved itself to be elusive due to various reasons. While this elusiveness can be partly attributed to the nature of the beast, other parts can be attributed to me.&lt;/p&gt;
&lt;p&gt;The idea minimalism puts forward is an enticing one, which can be simplified as "having no excess, but what you need", which brings many promises and possible outcomes with it. Out of these promises, there are two which attract me most:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduced mental load.&lt;/li&gt;
&lt;li&gt;Having more time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both of these promises stem from the argument that, if you have less possessions, you'll need less energy and time to manage them, and that's correct.&lt;/p&gt;
&lt;p&gt;However, while the idea is neat, it involves humans.&lt;/p&gt;
&lt;p&gt;I'm a curious, sometimes overly-curious, human being, and lack acquisition filters, partly because even if I don't have time, I have ample storage space to store and organization systems to remember what I want to come back to later. Material, or digital, it doesn't matter. As a result, while I'm a very organized person, I'm a crowded one at the same time.&lt;/p&gt;
&lt;p&gt;If I have the space, and the occasional time, what's the problem? Considering digital items don't take any physical space?&lt;/p&gt;
&lt;p&gt;The problems are numerous, and they're affecting much more than it looks.&lt;/p&gt;
&lt;p&gt;The first problem is the background pressure created by all the items in the back of my head. I already have a lengthy to do list which continues to grow steadily, and I'm not sure I can complete them all in a lifetime.&lt;/p&gt;
&lt;p&gt;The second problem is the crowdedness it creates in every living space. Physical and digital. Physical storage space becomes sparse as new gadgets and tools gets acquired, and every drive you open is full of folders. Putting them inside boxes or folders and labeling them "Organize this" doesn't help in any way. It's the same thing with pushing traumas to subconscious mind. They'll take up space in your closet, in your drive and in your mind, with the bonus of brewing at the background like a beer vat without sufficient pressure relief. Since the things you have put in these boxes are now harder to reach, it's possible that you'll re-acquire the same things again, which will further increase the space you use, with no added benefit.&lt;/p&gt;
&lt;p&gt;This visual and mental overload will take your energy, time and sanity away, because you'll spend more and more time to maintain something wobbly, trying to keep it upright (people who played &lt;a href="https://2dboy.com"&gt;World of Goo&lt;/a&gt; will understand).&lt;/p&gt;
&lt;p&gt;Remedying this requires fundamental shifts in one's mentality of storing, organizing and keeping things.&lt;/p&gt;
&lt;p&gt;First off, acquisition filters have the utmost importance, because if you can't stop the influx, reducing what you have will be sustaining the status quo at best. On the other hand, having no influx is not realistic, so preventing the unnecessary from entering is the best way.&lt;/p&gt;
&lt;p&gt;Secondly, you need to reduce what you have, right? This is one of the hardest parts of the whole process, because as humans, we tend to bond to things. Giving possessions away or deleting files feels like giving or throwing away parts of ourselves most of the time. As a result, this creates a lot of pain.&lt;/p&gt;
&lt;p&gt;However, all is not lost. For myself, I've found ways that work better than others. The simplest term summarizing it is "integration".&lt;/p&gt;
&lt;p&gt;Integration means opening the folders and boxes labeled "Organize these", and putting everything where it should be. If you feel that the file or the item shouldn't be there, it means you won't need it most probably. Put it somewhere visible, or the place where it should be nevertheless, and give it away or delete when you feel for it. It's not carefree, but makes the process easier.&lt;/p&gt;
&lt;p&gt;For material possessions which are perfectly functioning, throwing away is a huge betrayal for the item, the environment and the society in my view. I prefer donating them. Giving it away to someone  I won't be seeing again. When I don't see the item in question, I forget the item after some time.&lt;/p&gt;
&lt;p&gt;I'm going slowly, but making progress. As my life changes, space for my belongings is shrinking. Both material and digital. This change is urging me gently, but I'm not panicking.&lt;/p&gt;
&lt;p&gt;I'll document my journey and progress here, but I can't promise any regularity.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Fri, 22 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/meditations-on-minimalism/</guid></item><item><title>Python types for Data Scientists - Part III</title><link>https://bytepawn.com/python-types-for-data-scientists-part-iii.html</link><description>&lt;p&gt;I show slightly more advanced aspects of type checking in Python for Data Scientists.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Mypy" src="/images/mypy.png" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 22 Apr 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/python-types-for-data-scientists-part-iii.html</guid></item><item><title>Interview on Will Larson's Infrastructure Engineering</title><link>https://www.swyx.io/infra-eng-interview</link><description>&lt;p&gt;a reprint of my interview on Will Larson's InfraEng project.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Wed, 20 Apr 2022 10:36:02 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/infra-eng-interview</guid></item><item><title>React Miami: Temporal - React for the Backend</title><link>https://www.swyx.io/temporal-miami</link><description>&lt;p&gt;These are the raw notes of my talk prep for my React Miami 2022 talk - Temporal - React for the Backend. Includes links and initial draft at the bottom.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Tue, 19 Apr 2022 11:59:59 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/temporal-miami</guid></item><item><title>Interview With Phil of DataStation</title><link>http://notes.eatonphil.com/console-101.html</link><description>&lt;p&gt;This is an external interview. Click
&lt;a href="https://console.substack.com/p/console-101"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 17 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/console-101.html</guid></item><item><title>Python types for Data Scientists - Part II</title><link>https://bytepawn.com/python-types-for-data-scientists-part-ii.html</link><description>&lt;p&gt;I show slightly more advanced uses of type checking in Python.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Python snake" src="/images/python-hero.jpeg" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 17 Apr 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/python-types-for-data-scientists-part-ii.html</guid></item><item><title>Python tip 9: applying set-like operations for dictionaries</title><link>https://learnbyexample.github.io/tips/python-tip-9/</link><description>&lt;p&gt;You can merge two dictionaries using the &lt;code&gt;|&lt;/code&gt; operator (similar to union of sets). If a key is found in both the dictionaries, the insertion order of the first dictionary will be maintained, but the value of the second dictionary will be used. In other words, keys are updated to the new value during the merge.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;86&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;92&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_2 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Jo'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;89&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Joe'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# use unpacking, i.e. {**d1, **d2} for Python 3.8 and below versions
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;| &lt;/span&gt;&lt;span&gt;marks_2
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;86&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Jo'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;89&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Joe'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;code&gt;update()&lt;/code&gt; method if you want to modify instead of getting a new dictionary.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;update&lt;/span&gt;&lt;span&gt;(marks_2)
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;86&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Jo'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;89&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Joe'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;keys()&lt;/code&gt; and &lt;code&gt;values()&lt;/code&gt; dictionary methods return set-like objects, but with insertion order maintained. You get a set object as output when you apply set operators on these objects.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;86&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;92&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_2 &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Jo'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;89&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;78&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Joe'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;75&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;100&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# union of keys
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;| &lt;/span&gt;&lt;span&gt;marks_2.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Jo'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Joe'&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# common keys
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;amp; &lt;/span&gt;&lt;span&gt;marks_2.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Ravi'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rohit'&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# difference: keys not present in the other dict
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;- &lt;/span&gt;&lt;span&gt;marks_2.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_2.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;- &lt;/span&gt;&lt;span&gt;marks_1.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Jo'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Joe'&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# symmetric difference: union of above two differences
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;marks_1.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;^ &lt;/span&gt;&lt;span&gt;marks_2.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;keys&lt;/span&gt;&lt;span&gt;()
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Jo'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Joe'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'Rahul'&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Sat, 16 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-9/</guid></item><item><title>Vim tip 7: changing case in Normal mode</title><link>https://learnbyexample.github.io/tips/vim-tip-7/</link><description>&lt;p&gt;You can use the following commands to change the case of characters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;~&lt;/kbd&gt; invert the case of the character under the cursor (i.e. lowercase becomes UPPERCASE and vice versa)&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;g~&lt;/kbd&gt; followed by motion inverts the case of those characters
&lt;ul&gt;
&lt;li&gt;for example: &lt;kbd&gt;g~e&lt;/kbd&gt;, &lt;kbd&gt;g~$&lt;/kbd&gt;, &lt;kbd&gt;g~iw&lt;/kbd&gt;, etc &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;gu&lt;/kbd&gt; followed by motion changes those characters to lowercase
&lt;ul&gt;
&lt;li&gt;for example: &lt;kbd&gt;gue&lt;/kbd&gt;, &lt;kbd&gt;gu$&lt;/kbd&gt;, &lt;kbd&gt;guiw&lt;/kbd&gt;, etc &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;gU&lt;/kbd&gt; followed by motion changes those characters to UPPERCASE
&lt;ul&gt;
&lt;li&gt;for example: &lt;kbd&gt;gUe&lt;/kbd&gt;, &lt;kbd&gt;gU$&lt;/kbd&gt;, &lt;kbd&gt;gUiw&lt;/kbd&gt;, etc &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; You can also provide a count prefix to these commands. For example, &lt;kbd&gt;3~&lt;/kbd&gt; will invert the case of the current character and two characters to the right.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 12 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-7/</guid></item><item><title>Being powerless as a customer</title><link>https://blog.bayindirh.io/blog/being-powerless-as-a-customer/</link><description>&lt;p&gt;Web ecosystem has changed a lot in the recent years, esp. in the area of e-commerce, with the rise of cloud computing and subscription economy.&lt;/p&gt;
&lt;p&gt;With the evolving technology, many parts of an e-commerce system, or commerce parts of any website became increasingly commoditized. You need a payment processor? Paddle, Stripe, or any other alternative is there for you. Need to send files? SendOwl or just Amazon S3 with private, long links will do. Download limits? Add some transparent rules to these S3 links, or use a more sophisticated solution.&lt;/p&gt;
&lt;p&gt;These solutions are simple, yet incomplete and is not conductive to many things customers get accustomed to. Let's see some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Need your files again for any reason? You have to dig your emails to find the links. Unsurprisingly, at least one of them would be expired. So, you need to contact customer support, which may or may not provide the links for the files you've paid for. How about a dashboard to get a list of files and transactions for managing them yourself? Sorry. that's not provided by our platform.&lt;/li&gt;
&lt;li&gt;A mystery charge on your card? No worries, a receipt will arrive. It didn't? So, contact customer service, which may or may not give you answers about that charge. If you want to monitor them via a dashboard, you won't have any, because you should have received a receipt with relevant information and links in the first place, &lt;em&gt;but you didn't&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These examples are real experiences I have. All in all, if somehow the perfect workflow breaks for whatever reason, you have no power to reach anything, anyone or understand what's happening, and that's really crippling you as a customer.&lt;/p&gt;
&lt;p&gt;These problems are compounded when these events collide with a bigger company which is mostly enterprise oriented, but you're tech savvy enough to use their personal plans. You get lower tier support while paying for expensive subscriptions and get canned responses to your support requests. It's really making life harder.&lt;/p&gt;
&lt;p&gt;So, yes. The shiny product facades of integration companies have a dark side too. The seller gets a simple interface and a distributed tech stack which allows him/her to sleep better at night, but the customers served by that stack are in a worse state, and can't access to what they've bought and can't see why they paid this money again to the company.&lt;/p&gt;
&lt;p&gt;At that point the seller needs to help the customer, but it's not a given, and being left in the cold is a very bad feeling for a customer.&lt;/p&gt;
&lt;p&gt;If this trend continues to get adopted, looks like it'd be much more harder to cancel subscriptions, get our files back or just get support, and this means many unhappy customers, which will hopefully lead a change in the industry for the better.&lt;/p&gt;
&lt;p&gt;However, I'm not holding my breath, yet.&lt;/p&gt;</description><author>bayindirh</author><pubDate>Tue, 12 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.bayindirh.io/blog/being-powerless-as-a-customer/</guid></item><item><title>2022–04–12: Pinephone keyboard keymaps</title><link>https://xnux.eu/log/#066</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 12 Apr 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#066</guid></item><item><title>Lexicon Architectural Rubberducking</title><link>https://www.marginalia.nu/log/55-lexicon-rubberduck/</link><description>&lt;p&gt;I&amp;rsquo;m going to think out loud for a moment about a problem I&amp;rsquo;m considering.&lt;/p&gt;
&lt;p&gt;RAM is a precious resource on any server. Look at VPS servers, and you&amp;rsquo;ll be hard pressed to find one with much more than 32 Gb. Look at leasing a dedicated server, and it&amp;rsquo;s the RAM that really drives up the price. My server has 128 Gb, and it it&amp;rsquo;s so full it needs to unbutton its pants to sit down comfortably. Anything I can offload to disk is great.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Mon, 11 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/55-lexicon-rubberduck/</guid></item><item><title>Surveying SQL parser libraries in a few high-level languages</title><link>http://notes.eatonphil.com/sql-parsers.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-04-11-sql-parsers.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Mon, 11 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/sql-parsers.html</guid></item><item><title>Python types for Data Scientists - Part I</title><link>https://bytepawn.com/python-types-for-data-scientists.html</link><description>&lt;p&gt;I show how to use basic type hints and get type checking working in ipython notebooks.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Python types for Data Scientists" src="/images/python-data-types.jpeg" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 08 Apr 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/python-types-for-data-scientists.html</guid></item><item><title>The Bargain Bin B-Tree</title><link>https://www.marginalia.nu/log/54-bargain-bin-btree/</link><description>&lt;p&gt;I&amp;rsquo;ve been working lately on a bit of an overhaul of how the search engine does indexing. How it indexes its indices. &amp;ldquo;Index&amp;rdquo; is a bit of an overloaded term here, and it&amp;rsquo;s not the first that will crop up.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start from the beginning and build up and examine the problem of searching for a number in a list of numbers. You have a long list of numbers, let&amp;rsquo;s sort them because why not.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Thu, 07 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/54-bargain-bin-btree/</guid></item><item><title>Shakedown cruise on the Baltic Sea</title><link>https://bergie.iki.fi/blog/baltic-shakedown-cruise/</link><description>&lt;p&gt;Just in time for a new cruising season to start, the story of our &lt;a href="https://meri-imperiumi.github.io/log/2021/"&gt;2021 Baltic shakedown cruise&lt;/a&gt; is now online.&lt;/p&gt;

&lt;p&gt;&lt;img alt="In Swedish archipelago" src="https://d2vqpl3tx84ay5.cloudfront.net/500x/20210827_105504.jpg" /&gt; &lt;img alt="Sailing in the Baltic" src="https://d2vqpl3tx84ay5.cloudfront.net/500x/20210903_140900.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;This was a 666NM trip that we did on our new-to-us &lt;a href="https://meri-imperiumi.github.io/log/boat/"&gt;Amigo 40 cruising boat&lt;/a&gt; in August-September 2021. Apart from engine trouble in the beginning, this was a very enjoyable little adventure on the coasts of Sweden and Bornholm.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Trip route" src="https://d2vqpl3tx84ay5.cloudfront.net/800x/baltic-sea-shakedown-2021.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;The trip even earned us the first prize in the cruising log contest of &lt;a href="https://scgothia.de"&gt;our sailing club&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img alt="Fartenseglerpreise" src="https://d2vqpl3tx84ay5.cloudfront.net/500x/20220406_123935.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://meri-imperiumi.github.io/log/2021/"&gt;Read the story now&lt;/a&gt;.&lt;/p&gt;</description><author>Henri Bergius</author><pubDate>Thu, 07 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://bergie.iki.fi/blog/baltic-shakedown-cruise/</guid></item><item><title>CLI tip 8: extract from start of file until matching line</title><link>https://learnbyexample.github.io/tips/cli-tip-8/</link><description>&lt;p&gt;The &lt;code&gt;GNU sed&lt;/code&gt; command has a couple of handy commands to extract text from the start of input until a matching line is found. The &lt;code&gt;q&lt;/code&gt; and &lt;code&gt;Q&lt;/code&gt; commands are similar, except how they process the matching line.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;q&lt;/code&gt; command will exit &lt;code&gt;sed&lt;/code&gt; immediately, after printing the current pattern space if applicable.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# quit after a line containing 'st' is found
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'apple\nsea\neast\ndust' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; sed &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'/st/q'
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;sea
&lt;/span&gt;&lt;span&gt;east
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Q&lt;/code&gt; command is similar to &lt;code&gt;q&lt;/code&gt; but won't print the matching line.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span style="color: #7f8989;"&gt;# matching line won't be printed in this case
&lt;/span&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'apple\nsea\neast\ndust' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; sed &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'/st/Q'
&lt;/span&gt;&lt;span&gt;apple
&lt;/span&gt;&lt;span&gt;sea
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;tac+sed+tac&lt;/code&gt; will help you get lines starting from the last occurrence of the search string till the end of the input.&lt;/p&gt;
&lt;pre class="language-ruby " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-ruby"&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;printf &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'apple\nsea\neast\ndust\n' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; tac &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; sed &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'/ea/q' &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;|&lt;/span&gt;&lt;span&gt; tac
&lt;/span&gt;&lt;span&gt;east
&lt;/span&gt;&lt;span&gt;dust
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img alt="warning" src="/images/warning.svg" /&gt; Be careful if you want to use &lt;code&gt;q&lt;/code&gt; or &lt;code&gt;Q&lt;/code&gt; commands with multiple files, as &lt;code&gt;sed&lt;/code&gt; will stop even if there are other files left to be processed. You can use &lt;a href="https://learnbyexample.github.io/learn_gnused/selective-editing.html#address-range"&gt;mixed address ranges&lt;/a&gt; as a workaround. See also &lt;a href="https://unix.stackexchange.com/q/309514/109046"&gt;unix.stackexchange: applying q to multiple files&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See my &lt;a href="https://github.com/learnbyexample/learn_gnused"&gt;CLI text processing with GNU sed&lt;/a&gt; ebook if you are interested in learning about the &lt;code&gt;GNU sed&lt;/code&gt; command in more detail.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 06 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/cli-tip-8/</guid></item><item><title>Is There A Better Hard Drive Metaphor?</title><link>https://www.marginalia.nu/log/53-better-hard-drive-metaphor/</link><description>&lt;p&gt;This is mostly a post to complain about something that chafes. I wish there was a programming language (ideally several) that acknowledged that computers have hard drives, not just a processor, RAM and other_devices[].&lt;/p&gt;
&lt;p&gt;Something that has struck me when I&amp;rsquo;ve been working with the search engine is how unfinished the metaphor for accessing physical disks is in most programming languages. It feels like an after-thought, half left to the operating system to figure out, a byzantine relic of the days when computers had tape drives and not SSDs.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Sun, 03 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/53-better-hard-drive-metaphor/</guid></item><item><title>A Conversational Bill of Rights</title><link>https://jodavaho.io/posts/conversation-bill-of-rights.html</link><description>&lt;p&gt;Feel free to issue a pull request or file issues at &lt;a href="https://github.com/jodavaho/conversation_rights"&gt;github.com/jodavaho/conversational_rights&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="preamble"&gt;Preamble&lt;/h1&gt;
&lt;p&gt;The ability of humans to exchange information quickly and efficiently is our super power. Our other limited abilities and general fragility could not have made us the dominant species of the entire planet, and enabled us to do the things we do. More specifically, the written and verbal expression of culture has enabled the alignment of the individuals of our species toward long term goals of incredible complexity.  So pervasive is our reliance on verbal and written communication that I believe it deserves to be considered a fundamental right. Moreover, it is imperative to establish norms in the &lt;em&gt;kinds&lt;/em&gt; of exchanges and how they evolve, and what ideas are allowed or what cross examinations are considered polite and welcome, if only to increase the quality of discourse for exchangers and observers alike.&lt;/p&gt;
&lt;h1 id="rights-in-the-exchange-of-information-and-culture"&gt;Rights in the exchange of information and culture&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A clear understanding of the issue and main points is critical to make thoughtful and useful contributions to the issue at hand. Thus, in any conversation, be it written or spoken, You have the right to remain silent. You have the right to withhold judgement and contributions, and to have your act of remaining silent remain free of any perceived agenda &amp;ndash; not condoning or condemning any part of any point of any argument in any conversation or exchange of information. The silent party has no obligation to state why they are remaining silent or withholding contributions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have the right to have your contributions interpreted in the most favorable light. It is not the responsibility of the contributor to specify the full context of any contribution. It is the responsibility of the reader / listener to request clarification whenever ambiguity presents various interpretations which are both favorable and unfavorable, either in the receivers&amp;rsquo; own mind(s) or on behalf of possible misunderstandings by other observers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learning and maturation is inevitable and good in any person or organization. Thus, you have the right to express a change in past contributions, and to make updated contributions that overrule your past contributions, whenever those past contributions are referenced as part of this change.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Even if your contribution&amp;rsquo;s thesis has not changed, you have the right to clarify past contributions, and to have the most recent clarification override the past contributions &amp;ndash; to the extent that they do not overtly contradict those past contributions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have the right to request clarification on any point made by any contributor. The requestee is not bound by any special constraints, and retains all the rights herein. Furthermore, you have the right to request supporting information, context, or background information of any opinion or statement. Such requests shall not in themselves be viewed as a malicious act.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have the right to pronounce judgement and opinion for or against any contribution or argument by any party as part of your contribution. No party is under any obligation to acknowledge or respond to any pronunciation thereof.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In order to allow context and clear train of thought by a contributor, you have the right to request uninterrupted time or space to present an argument, and to withhold any contributions or information unless that time is given.  Similarly, you have the right to request a limit to the uninterrupted time or space given to any party, and are under no obligation to consider discourse that continues outside of this time or space, should they agree to those limits.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have the right to specify the audience for your arguments. That is, you have the right to make any statement or express an opinion without the intent to convince the listener, for example to make it part of the conversation record or be it part of posterity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have the right to request and /or specify a structure for the exchange of information. These &amp;ldquo;rules of order&amp;rdquo; shall be agreed to by all parties or not used, and shall apply to all parties equally, with the exception of an optional &amp;ldquo;moderator&amp;rdquo; who directs the conversation according to the rules. If used, the moderator shall act impartially and shall be precluded from contributing to the exchange. Specifically, you have the right to request a moderator in any exchange of information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have the right to request limited or expanded audience. You can, at any time, request that an exchange of information or dialog be conducted in the party of any  observer(s) (or in private), and to withhold your contributions if this is not agreed to. The observer is under no obligation to keep their observations confidential unless agreed upon by all parties.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="license"&gt;License&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://creativecommons.org/licenses/by-sa/4.0/deed.ast"&gt;CC BY-SA 4.0&lt;/a&gt;&lt;/p&gt;</description><author>jodavaho.io</author><pubDate>Sat, 02 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jodavaho.io/posts/conversation-bill-of-rights.html</guid></item><item><title>2022–04–02: Pinephone keyboard power manager</title><link>https://xnux.eu/log/#065</link><author>megi's PinePhone Development Log</author><pubDate>Sat, 02 Apr 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#065</guid></item><item><title>April 2022 update on my RPG projects</title><link>https://benovermyer.com/blog/2022/04/april-2022-update-on-rpgs/</link><description>&lt;p&gt;It's been quite some time since I last wrote about the tabletop RPG projects I have in the works.&lt;/p&gt;
&lt;p&gt;For the most part, there have been very few updates over the last year. However, I have been occasionally plinking away at the Ingenium Second Edition manuscript, and lately I've been planning on how to bring a few others closer to completion.&lt;/p&gt;
&lt;h2 id="updates-on-existing-projects"&gt;Updates on existing projects&lt;/h2&gt;
&lt;p&gt;Ingenium Second Edition has seen the bulk of the work. Species were renamed to bloodlines. An entire continent was removed from the setting. A lot of things were reworked for the 2d6 core mechanic. A lot of Talents and spells were added. Professions got organizations that you have a relationship with starting out. A languages index was added. All of the remaining Talents were planned out. Most were fleshed out. Wizard marks were made a core part of the magic system instead of a Talent.&lt;/p&gt;
&lt;p&gt;Mysteries of a Broken World was... just converted to LaTeX. Nothing substantial changed here.&lt;/p&gt;
&lt;p&gt;Vox Draconis: Kingdoms of Stone and Fire similarly had little done to it. A few cosmetic changes and typo fixes.&lt;/p&gt;
&lt;h2 id="plans-for-the-future"&gt;Plans for the future&lt;/h2&gt;
&lt;p&gt;I'm going to continue to bring Ingenium Second Edition closer to completion. It remains my primary focus. I plan on doing all of the work myself, including layout and illustration. For the immediate future I'm going to focus on writing all of the spells, miracles, spirit tricks, and Talents.&lt;/p&gt;
&lt;p&gt;Mysteries of a Broken World is going to get the most dramatic change of the three. I'm going to rework it to be purely a solo RPG. The survival theme will get stronger, since there will no longer be other players to worry about.&lt;/p&gt;
&lt;p&gt;Vox Draconis: Kingdoms of Stone and Fire will probably see the least work this year. It's a tight concept and really just needs fleshing out rather than any system development. From time to time I'll add to it, but Ingenium will take up more of my attention.&lt;/p&gt;
&lt;p&gt;Lastly, I plan on formally adding Ingenium Second Edition to this website. The trademark and copyright are mine now instead of Silver Gryphon Games'. I'll make a bigger post about this later.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Fri, 01 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/04/april-2022-update-on-rpgs/</guid></item><item><title>Who Controls a DAO?</title><link>https://specbranch.com/posts/who-controls-a-dao/</link><description>&lt;p&gt;In honor of April Fools' Day, I decided to write about a blockchain topic. The crypto economy is in
the process of speedrunning their way from zero to a modern economy, and when you move that fast,
a few things have to break along the way.  One of those things is corporate governance.&lt;/p&gt;
&lt;p&gt;Matt Levine's &lt;a href="https://www.bloomberg.com/opinion/authors/ARbTQlRLRjE/matthew-s-levine"&gt;&amp;quot;Money Stuff&amp;quot;&lt;/a&gt;
is a financial newsletter that I can't recommend enough.  If you are at all interested in finance,
stocks, and markets, it is funny and informative read.  One of the recurring topics of Money Stuff
is &amp;quot;who controls a company?&amp;quot;  Quoting a bit of the
&lt;a href="https://www.bloomberg.com/opinion/articles/2018-07-24/papa-john-s-poison-pilled-papa-john?sref=1kJVNqnU"&gt;newsletter&lt;/a&gt;:&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Fri, 01 Apr 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/who-controls-a-dao/</guid></item><item><title>Vim Reference Guide: two week sales report</title><link>https://learnbyexample.github.io/mini/vim-reference-guide-sales/</link><description>&lt;p&gt;I've previously written about events and strategies that led to &lt;a href="https://learnbyexample.github.io/wild-ride-2021/#book-sales"&gt;increased ebook sales during the last quarter of 2021&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Very pleased to inform that I continue to see more than expected sales. I had released my 12th ebook &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; on March 15th. Here's how the sales looked on Gumroad during the first two weeks:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img alt="Two week Gumroad sales chart" src="/images/vim-release-gumroad-sales.png" /&gt;&lt;/p&gt;
&lt;p&gt;I used to offer my ebooks for free on release. For the past couple of releases, I have also added heavily discounted ebook bundles which seems to be the major factor in increased paid sales I'm seeing. Luck certainly plays a role too, reaching front page of Hacker News and top of subreddits cannot be always counted upon. Here are some of the ways I promoted my latest ebook:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnbyexample.gumroad.com/p/announcing-vim-reference-guide-free-discount-offers-and-more"&gt;Announcement post on Gumroad&lt;/a&gt; and sending an email to existing readers&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=30684232"&gt;Show HN post on Hacker News&lt;/a&gt;, got lucky to be placed in top 10&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/learn_byexample/status/1503752985708736512"&gt;Pinned tweet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Posting on &lt;a href="https://www.reddit.com/r/commandline/comments/tjzxn9/i_wrote_a_vim_reference_guide/"&gt;/r/commandline/&lt;/a&gt; and &lt;a href="https://www.reddit.com/r/linux/comments/toll6i/i_wrote_a_vim_reference_guide/"&gt;/r/linux/&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;You might wonder why not /r/vim? Somebody else posted before I could, and unfortunately it got downvoted. I'll probably make my own post after I release the next version&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/SyQe6zzOGZ0"&gt;Promo video on youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mentioned in two of my &lt;a href="https://learnbyexample.gumroad.com/l/learnbyexample-weekly"&gt;learnbyexample weekly&lt;/a&gt; newsletter issues&lt;/li&gt;
&lt;li&gt;And of course, I wrote a release post &lt;a href="https://learnbyexample.github.io/vim-reference-guide-announcement/"&gt;on this blog&lt;/a&gt; and also mentioned it on my &lt;a href="https://github.com/learnbyexample"&gt;GitHub Readme&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Apart from Gumroad, 500+ readers downloaded the guide from &lt;a href="https://leanpub.com/vim_reference_guide"&gt;Leanpub&lt;/a&gt; and I got a few paid sales as well. I wrote about &lt;a href="https://learnbyexample.github.io/my-book-writing-experience/#leanpub-vs-gumroad"&gt;pros and cons of Gumroad/Leanpub here&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; PS: Make sure to read the rules and be a regular user before self-promoting your content on the social media platforms mentioned above.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Thu, 31 Mar 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/mini/vim-reference-guide-sales/</guid></item><item><title>2022–03–31: Keyboard light</title><link>https://xnux.eu/log/#064</link><author>megi's PinePhone Development Log</author><pubDate>Thu, 31 Mar 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#064</guid></item><item><title>Python tip 8: dict.fromkeys() method</title><link>https://learnbyexample.github.io/tips/python-tip-8/</link><description>&lt;p&gt;A lesser known way to create a dictionary is to use the &lt;code&gt;fromkeys()&lt;/code&gt; method that accepts an iterable and an optional value (default is &lt;code&gt;None&lt;/code&gt;). The same value will be assigned to all the keys, so be careful if you want to use a mutable object.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;colors &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'red'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'blue'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'green'&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;dict&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;fromkeys&lt;/span&gt;&lt;span&gt;(colors)
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'red'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;None&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'blue'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;None&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'green'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;None&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;dict&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;fromkeys&lt;/span&gt;&lt;span&gt;(colors, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;255&lt;/span&gt;&lt;span&gt;)
&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'red'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;255&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'blue'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;255&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'green'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;255&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you iterate over a dictionary object, you'll get only the keys. For example:&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;fruits &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span style="color: #d07711;"&gt;'banana'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;12&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'papaya'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #d07711;"&gt;'mango'&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;10&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; for &lt;/span&gt;&lt;span&gt;fruit &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;in &lt;/span&gt;&lt;span&gt;fruits:
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;...     &lt;/span&gt;&lt;span style="color: #b39f04;"&gt;print&lt;/span&gt;&lt;span&gt;(fruit)
&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;... 
&lt;/span&gt;&lt;span&gt;banana
&lt;/span&gt;&lt;span&gt;papaya
&lt;/span&gt;&lt;span&gt;mango
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recent Python versions ensure that the insertion order is maintained for a dictionary. So, you can remove duplicate items from a list while maintaining the order by building a dictionary using the &lt;code&gt;fromkeys()&lt;/code&gt; method and converting it back to a list.&lt;/p&gt;
&lt;pre class="language-python " style="background-color: #f5f5f5; color: #1f1f1f;"&gt;&lt;code class="language-python"&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span&gt;nums &lt;/span&gt;&lt;span style="color: #72ab00;"&gt;= &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;22&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;51&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# remove duplicates, if you don't care about the element order
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;list&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #a2a001;"&gt;set&lt;/span&gt;&lt;span&gt;(nums))
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;51&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;22&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span style="color: #7f8989;"&gt;# remove duplicates, if you want to maintain the element order
&lt;/span&gt;&lt;span style="color: #72ab00;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color: #a2a001;"&gt;list&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #a2a001;"&gt;dict&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span style="color: #5597d6;"&gt;fromkeys&lt;/span&gt;&lt;span&gt;(nums))
&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style="color: #b3933a;"&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;22&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #b3933a;"&gt;51&lt;/span&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/100_page_python_intro"&gt;100 Page Python Intro&lt;/a&gt; ebook.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 30 Mar 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/python-tip-8/</guid></item><item><title>Writing a document database from scratch in Go: Lucene-like filters and indexes</title><link>http://notes.eatonphil.com/documentdb.html</link><description>&lt;p&gt;In this post we'll write a rudimentary document database from scratch
in Go. In less than 500 lines of code we'll be able to support the
following interactions, inspired by Elasticsearch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-X&lt;span class="w"&gt; &lt;/span&gt;POST&lt;span class="w"&gt; &lt;/span&gt;-H&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'{&amp;quot;name&amp;quot;: &amp;quot;Kevin&amp;quot;, &amp;quot;age&amp;quot;: &amp;quot;45&amp;quot;}'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;5ac64e74-58f9-4ba4-909e-1d5bf4ddcaa1&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;

$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=name:&amp;quot;Kevin&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq
&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;45&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Kevin&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;5ac64e74-58f9-4ba4-909e-1d5bf4ddcaa1&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=age:&amp;lt;50'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq
&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;45&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Kevin&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;5ac64e74-58f9-4ba4-909e-1d5bf4ddcaa1&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The latter query, being a range query, will do a full table scan. But
the first query, an exact match, will use an index and be much
faster.&lt;/p&gt;
&lt;p class="note"&gt;
  Document databases in general may be able to support indexes on
  ranges but our rudimentary one won't.
  &lt;br /&gt;
  &lt;br /&gt;
  Furthermore, this post will not implement full text search.
&lt;/p&gt;&lt;p&gt;All code for this project is &lt;a href="https://github.com/eatonphil/docdb"&gt;available on
Github&lt;/a&gt;. Let's get started.&lt;/p&gt;
&lt;h3 id="server-basics"&gt;Server basics&lt;/h3&gt;&lt;p&gt;Run &lt;code&gt;go mod init&lt;/code&gt; and set up &lt;code&gt;main.go&lt;/code&gt; with &lt;a href="https://github.com/julienschmidt/httprouter"&gt;Julien Schmidt's
httprouter&lt;/a&gt;. We'll create
three routes: one for inserting a document, one for retrieving a
document by its id, and one for searching for documents.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;encoding/json&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;net/http&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/julienschmidt/httprouter&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;8080&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addDocument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs/:id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Listening on &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now add the routes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;addDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unimplemented&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;searchDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unimplemented&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unimplemented&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's good enough for now! Let's think about storage.&lt;/p&gt;
&lt;h3 id="storage"&gt;Storage&lt;/h3&gt;&lt;p&gt;If you wanted to do this project fully from scratch you could handle
storage by just writing JSON blobs to disk. Nothing in this project
will be much more complex than just writing JSON to disk and the
equivalent of using &lt;code&gt;ls&lt;/code&gt; on the filesystem. I mention this because I
said this project is "from scratch" but I'm going to bring in a
storage engine. My point is that you could easily follow this post and
just read/write directly to disk if you felt strongly.&lt;/p&gt;
&lt;p class="note"&gt;
  Because there were so many folks misconstruing this paragraph, I've
  ported this blog post without Pebble as proof :D. You
  can &lt;a href="https://github.com/eatonphil/docdb/pull/1"&gt;find the
  diff here&lt;/a&gt;. Took me an hour for the +40/-40 diff that is still
  &lt;500 lines of code. You may notice the code basically looks
  identical. That's because the storage engine isn't the interesting
  part. :)
&lt;/p&gt;&lt;p&gt;Any storage engine would be fine: direct read/write, SQLite,
PostgreSQL. But we're going to grab a key-value storage engine. I've
used Badger before so I'm going to try out &lt;a href="https://github.com/cockroachdb/pebble"&gt;Cockroach Lab's
Pebble&lt;/a&gt; this time instead.&lt;/p&gt;
&lt;p&gt;Add &lt;code&gt;"github.com/cockroachdb/pebble"&lt;/code&gt; to the list of imports. Then
upgrade the &lt;code&gt;server&lt;/code&gt; struct to store an instance of a Pebble database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And upgrade main:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;docdb.data&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;8080&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addDocument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs/:id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Listening on &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the future these server settings could be user-configurable. For
now they're hard-coded.&lt;/p&gt;
&lt;h4 id="storing-data"&gt;Storing data&lt;/h4&gt;&lt;p&gt;When the user sends a JSON document we need to give it a unique ID and
store the ID and document in the database. Since we're using a
key-value storage engine we'll just use the ID as the key and the JSON
document as the value.&lt;/p&gt;
&lt;p&gt;To generate the ID we'll use &lt;a href="https://github.com/google/uuid"&gt;Google's UUID
package&lt;/a&gt;. So make sure to import
&lt;code&gt;"github.com/google/uuid"&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;addDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// New unique id for the document&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nothing special: just accept a JSON POST body and store it in the
database, return the generated document id.&lt;/p&gt;
&lt;p class="note"&gt;
  I'm not sure that using UUIDs here is a good idea but it is easier
  than keeping track of the number of rows in the database.
&lt;/p&gt;&lt;p&gt;The &lt;code&gt;jsonResponse&lt;/code&gt; helper can be defined as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;enc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;enc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// TODO: set up panic handler?&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It's a basic wrapper so that all responses are structured JSON.&lt;/p&gt;
&lt;h4 id="retrieving-by-id"&gt;Retrieving by ID&lt;/h4&gt;&lt;p&gt;Before we try to test out inserts, let's get retrieval hooked
up. Inserts return an ID in the HTTP reponse. GETs will grab a
document by ID.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getDocumentById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;valBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;closer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;closer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDocumentById&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;document&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We've now got enough in place to test out these basics!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;mod&lt;span class="w"&gt; &lt;/span&gt;init&lt;span class="w"&gt; &lt;/span&gt;docdb
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;mod&lt;span class="w"&gt; &lt;/span&gt;tidy
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
$&lt;span class="w"&gt; &lt;/span&gt;./docdb
&lt;span class="m"&gt;2022&lt;/span&gt;/03/28&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;:28:19&lt;span class="w"&gt; &lt;/span&gt;Listening&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, in another terminal, insert a document:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-X&lt;span class="w"&gt; &lt;/span&gt;POST&lt;span class="w"&gt; &lt;/span&gt;-H&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'{&amp;quot;name&amp;quot;: &amp;quot;Kevin&amp;quot;, &amp;quot;age&amp;quot;: &amp;quot;45&amp;quot;}'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;c458a3ce-9faf-4431-a058-d9ae2a1651e1&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;

$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs/c458a3ce-9faf-4431-a058-d9ae2a1651e1
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;document&amp;quot;&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;45&amp;quot;&lt;/span&gt;,&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;Kevin&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}}&lt;/span&gt;,&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Perfect! Now let's implement search.&lt;/p&gt;
&lt;h3 id="a-filter-language"&gt;A filter language&lt;/h3&gt;&lt;p&gt;First off we need to pick a filter language. Using a JSON data
structure would be fine. We could require the user POSTs against a
search endpoint so that the POST body contains the JSON filter.&lt;/p&gt;
&lt;p&gt;But &lt;a href="https://lucene.apache.org/core/2_9_4/queryparsersyntax.html"&gt;Lucene&lt;/a&gt; is a pretty simple language and we can implement enough
parts of it easily. The result is more fun.&lt;/p&gt;
&lt;p&gt;In our simplification of Lucene there will only be key-value
matches. Field names and field values can be quoted. They must be
quoted if they contain spaces or colons, among other things. Key-value
matches are separated by whitespace. They can only be AND-ed together
and that is done implicitly.&lt;/p&gt;
&lt;p&gt;The following are some valid filters in our implementation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;a:1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b:fifteen a:&amp;lt;3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a.b:12&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;title:"Which way?"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;" a key 2":tenant&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;" flubber ":"blubber "&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nested paths are specified using JSON path syntax (i.e. &lt;code&gt;a.b&lt;/code&gt; would
retrieve &lt;code&gt;4&lt;/code&gt; in &lt;code&gt;{"a": {"b": 4, "d": 100}, "c": 8}&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id="lexing-strings"&gt;Lexing strings&lt;/h3&gt;&lt;p&gt;Both keys and values are lexed as strings. If they start with a quote,
we keep on accumulating all characters until the ending
quote. Otherwise we accumulate until we stop seeing a digit, letter,
or period.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Handles either quoted strings or unquoted strings of only contiguous digits and letters&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;foundEnd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;rune&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// TODO: handle nested quotes&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'&amp;quot;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;foundEnd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;foundEnd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Expected end of quoted string&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// If unquoted, read as much contiguous digits/letters as there are&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;rune&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;rune&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// TODO: someone needs to validate there's not ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!(&lt;/span&gt;&lt;span class="nx"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IsLetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IsDigit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;No string found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  This is not something you get right without unit tests. I wrote unit
  tests for it while building this project. Always unit test tricky code
  where you're likely to have off-by-one errors! I had a bunch.
&lt;/p&gt;&lt;h3 id="query-parser"&gt;Query parser&lt;/h3&gt;&lt;p&gt;Now we can write the query parser. It first lexes a string for the
key. Then it looks for the operator which can be one of &lt;code&gt;:&lt;/code&gt; (meaning
equality), &lt;code&gt;:&amp;gt;&lt;/code&gt; (meaning greater than), or &lt;code&gt;:&amp;lt;&lt;/code&gt; (meaning less
than). It accumulates each key-value pair into an overall list of
AND-ed arguments that make up the query.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queryComparison&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ands&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;queryComparison&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parseQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qRune&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qRune&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Eat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;whitespace&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unicode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qRune&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qRune&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Expected valid key, got [&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;]: `&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;`&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Expect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Expected colon at &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;, got: `&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;`&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qRune&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Expected valid value, got [&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;]: `&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;`&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextIndex&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queryComparison&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ands&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ands&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we're already writing a real lexer we could do better than
&lt;code&gt;strings.Split(key, ".")&lt;/code&gt; when it comes to find key path parts. But it
isn't a huge deal at this stage. So we keep it simple.&lt;/p&gt;
&lt;h3 id="query-matching"&gt;Query matching&lt;/h3&gt;&lt;p&gt;Now that we've got the query parser we need to implement an evaluator
for the search endpoint. We need to be able to check that given a
document, it meets the filter or not.&lt;/p&gt;
&lt;p&gt;So we iterate over each argument and do the indicated comparison:
equality, greater than or less than. If at any point the comparison
fails, return false immediately. Otherwise if we got through all
arguments and didn't return, there was a match!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ands&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Handle equality&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Handle &amp;lt;, &amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ParseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int16&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ParseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  This bit of Go that requires separate case statements for every
  possible numeric so I can convert it to float is really annoying.
&lt;/p&gt;&lt;p&gt;The only additional part to call out in there is &lt;code&gt;getPath&lt;/code&gt;. We need to
be able to grab any path within an object since the user could have
made a filter like &lt;code&gt;a.b:12&lt;/code&gt;. So let's keep things simple (but less
safe) and implement &lt;code&gt;getPath&lt;/code&gt; recursively.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docSegment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docSegment&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docSegment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docSegment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A critical thing to point out is that filtering on arrays is not
supported. Any filter that tries to enter an array will fail or return
no results.&lt;/p&gt;
&lt;h3 id="search"&gt;Search&lt;/h3&gt;&lt;p&gt;Now that we've got all the tools in place we can implement the search
endpoint. We'll just iterate over all documents in the database and
return all documents that match the filter.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;searchDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parseQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;q&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewIter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not bad! Let's try it out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
$&lt;span class="w"&gt; &lt;/span&gt;./docdb
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And in another terminal, try out the search endpoint with no filter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq
&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;45&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Kevin&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;c458a3ce-9faf-4431-a058-d9ae2a1651e1&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With an equality filter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=name:Mel'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq
&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;null
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=name:Kevin'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq
&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;45&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Kevin&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;c458a3ce-9faf-4431-a058-d9ae2a1651e1&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And with greater than/less than filters:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=age:&amp;lt;12'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq
&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;null
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=age:&amp;lt;200'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq
&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;45&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Kevin&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;c458a3ce-9faf-4431-a058-d9ae2a1651e1&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Sweet.&lt;/p&gt;
&lt;h3 id="benchmarking"&gt;Benchmarking&lt;/h3&gt;&lt;p&gt;Now let's try inserting a few hundred thousand rows of real-world
data. Grab &lt;code&gt;movies.json&lt;/code&gt; from the &lt;a href="https://github.com/prust/wikipedia-movie-data"&gt;Wikipedia Movie Data
repo&lt;/a&gt;. This dataset
only has 28,000 rows. But we can insert it multiple times. If we
filter by movie name and movie year we'll be looking at only a small
subset of the data but enough that we can get a sense about
performance.&lt;/p&gt;
&lt;p&gt;Here's a basic script to ingest that data a bunch of times once you've
downloaded the file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e

&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;..50&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.[]'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-X&lt;span class="w"&gt; &lt;/span&gt;POST&lt;span class="w"&gt; &lt;/span&gt;-H&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Start it up and wait as long as you can. :)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;+x&lt;span class="w"&gt; &lt;/span&gt;scripts/load_array.sh
$&lt;span class="w"&gt; &lt;/span&gt;./scripts/load_array.sh&lt;span class="w"&gt; &lt;/span&gt;movies.json
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can check how many items are in the database like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.body.count'&lt;/span&gt;
&lt;span class="m"&gt;12649&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once you have a few hundred thousand documents you'll start to notice
exact equality queries start to take longer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=&amp;quot;year&amp;quot;:1918'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.body.count'&lt;/span&gt;
&lt;span class="m"&gt;1152&lt;/span&gt;
curl&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=&amp;quot;year&amp;quot;:1918'&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.992&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And you think: although there are hundreds of thousands of documents,
if I'm just asking for documents with a certain value such that there
are only 1000 documents that match that value, shouldn't it be
possible to grab them more quickly than in one whole second? Or, better
than a time that grows with the number of documents in the database?&lt;/p&gt;
&lt;p&gt;Yes. Yes it is possible.&lt;/p&gt;
&lt;h3 id="indexes"&gt;Indexes&lt;/h3&gt;&lt;p&gt;Document databases often index everything. We're going to do that. For
every path in a document (that isn't a path within an array) we're
going to store the path and the value of the document at that path.&lt;/p&gt;
&lt;p&gt;First we'll open a second database that we'll use to store all of
these path-value pairs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Primary data&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;indexDb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Index data&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.index&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then when we insert, we'll call an &lt;code&gt;index&lt;/code&gt; function to generate all
path-value pairs and store them in this second database.&lt;/p&gt;
&lt;p&gt;The index database will store the path-value pair as keys. And values
will be the comma separated list of document IDs that have that
path-value pair.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;pv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getPathValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pathValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;closer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathValue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ErrNotFound&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not look up pathvalue [%#v]: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;existingId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;existingId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;closer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;closer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not close: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathValue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not update index: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Keeping things simple we'll also implement this &lt;code&gt;getPathValues&lt;/code&gt; helper
recursively:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getPathValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pvs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;pvs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pvs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getPathValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}:&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// Can't handle arrays&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;pvs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pvs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s=%v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pvs&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We'll update one line in &lt;code&gt;s.addDocument&lt;/code&gt; to call this &lt;code&gt;index&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;addDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// New unique id for the document&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we'll add a &lt;code&gt;reindex&lt;/code&gt; function to be called in &lt;code&gt;main&lt;/code&gt; to handle
any documents that were ingested and not indexed (i.e. all the ones we
already inserted).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;reindex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewIter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unable to parse bad document, %s: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;docdb.data&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;8080&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reindex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addDocument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/docs/:id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Listening on &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="using-the-index"&gt;Using the index&lt;/h3&gt;&lt;p&gt;When there is an equality filter we can look the equality filter
up in the index database. Our filter language only supports AND-ed
arguments. So the results matching the overall filter must be the set
intersection of ids that match each individual equality
filter. Greater than and less than filters will be filtered out after
fetching all possible ids that match equality filters.&lt;/p&gt;
&lt;p&gt;If no ids are found in the index database meeting all equality filters
then we'll fall back to the full table scan we already have.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;searchDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;httprouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parseQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;q&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;isRange&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;idsArgumentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;nonRangeArguments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ands&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;nonRangeArguments&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s=%v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idsArgumentCount&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="nx"&gt;idsArgumentCount&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;idsArgumentCount&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;isRange&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idsInAll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idsArgumentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nonRangeArguments&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;idsInAll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idsInAll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;skipIndex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;idsInAll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idsInAll&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idsInAll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDocumentById&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isRange&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewIter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;documents&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The last unimplemented part is the &lt;code&gt;lookup&lt;/code&gt; helper. Given a path-value
pair it checks the database for IDs that match that pair.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;closer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathValue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pebble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ErrNotFound&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not look up pathvalue [%#v]: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pathValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;closer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;closer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idsString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We're done. Finally! Let's build it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
$&lt;span class="w"&gt; &lt;/span&gt;./docdb
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(This is going to take a while; to reindex.)&lt;/p&gt;
&lt;p&gt;Once the server is ready we can run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=&amp;quot;year&amp;quot;:1918'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.body.count'&lt;/span&gt;
&lt;span class="m"&gt;1280&lt;/span&gt;
curl&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;--get&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8080/docs&lt;span class="w"&gt; &lt;/span&gt;--data-urlencode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'q=&amp;quot;year&amp;quot;:1918'&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.01s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.029&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hey that's not bad.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Hey here's a new blog post on writing a document database from scratch with support for Lucene-like queries and basic indexes in less than 500 lines of Go&lt;a href="https://t.co/M3js6Pj9h0"&gt;https://t.co/M3js6Pj9h0&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1508546397943046150?ref_src=twsrc%5Etfw"&gt;March 28, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Mon, 28 Mar 2022 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/documentdb.html</guid></item><item><title>Solving 5 algorithmic interview questions</title><link>https://bytepawn.com/solving-5-algorithmic-interview-questions.html</link><description>&lt;p&gt;Recently I was considering whether to introduce some CS style algorithmic interview questions into our Data Science hiring loop, since having an understanding of algorithms and data structures can be useful for Data Scientists. Not having done this soft of interview for a few years I picked up my copy of &lt;a href="https://www.amazon.com/Daily-Coding-Problem-exceptionally-interviews/dp/1793296634"&gt;Daily Coding Problem&lt;/a&gt; and starting solving a few problems to refresh my feeling for what it feels like as a candidate, and whether it would give us any useful signals.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Daily coding problem" src="https://d1w7fb2mkkr3kw.cloudfront.net/assets/images/book/lrg/9781/7932/9781793296634.jpg" style="width: 200px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 26 Mar 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/solving-5-algorithmic-interview-questions.html</guid></item><item><title>Vim tip 6: search word nearest to the cursor</title><link>https://learnbyexample.github.io/tips/vim-tip-6/</link><description>&lt;p&gt;Vim provides handy commands to match words under (or near to) the cursor. You can choose to match whole or part of a longer word. If a match is found, the cursor will move to the next match in the chosen direction.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;*&lt;/kbd&gt; searches the word nearest to the cursor in the forward direction (matches only the whole word)
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Shift&lt;/kbd&gt; followed by &lt;strong&gt;left mouse click&lt;/strong&gt; can also be used if mouse is enabled&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;g*&lt;/kbd&gt; searches the word nearest to the cursor in the forward direction (matches as part of another word as well)
&lt;ul&gt;
&lt;li&gt;for example, if you apply this command on the word &lt;code&gt;the&lt;/code&gt;, you'll also get matches for &lt;code&gt;them&lt;/code&gt;, &lt;code&gt;lather&lt;/code&gt;, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;#&lt;/kbd&gt; searches the word nearest to the cursor in the backward direction (matches only the whole word)&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;g#&lt;/kbd&gt; searches the word nearest to the cursor in the backward direction (matches as part of another word as well)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From &lt;a href="https://vimhelp.org/motion.txt.html#word"&gt;:h word&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A word consists of a sequence of letters, digits and underscores, or a sequence of other non-blank characters, separated with white space (spaces, tabs, &lt;code&gt;&amp;lt;EOL&amp;gt;&lt;/code&gt;). This can be changed with the &lt;code&gt;iskeyword&lt;/code&gt; option.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sequence of non-blank characters will be used only at the end of the line. Otherwise, the above commands will use the next word found on that line which is made up of letters, digits and underscores.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; You can also provide a count prefix to these commands. For example, &lt;kbd&gt;2*&lt;/kbd&gt; will take you to the second match in the forward direction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Thu, 24 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-6/</guid></item><item><title>Growing Pains</title><link>https://www.marginalia.nu/log/52-growing-pains/</link><description>&lt;p&gt;The search engine index has grown quite considerably the last few weeks. It&amp;rsquo;s actually surpassed 50 million documents, which is quite some milestone. In February it was sitting at 27-28 million or so.&lt;/p&gt;
&lt;p&gt;About 80% of this is side-loading all of stackoverflow and stackexchange, and part of it is additional crawling.&lt;/p&gt;
&lt;p&gt;The crawler has to date fetched 91 million URLs, but only about a third of what is fetched actually qualifies for indexing for various reasons, some links may be dead, some may be redirects, some may just have too much javascript and cruft to qualify.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Wed, 23 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/52-growing-pains/</guid></item><item><title>Fair coin from biased coin</title><link>https://bytepawn.com/fair-coin-from-biased-coin.html</link><description>&lt;p&gt;Given a biased coin, construct a fair coin.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Fair coin from biased coin" src="https://www.epic-escapes.games/wp-content/uploads/2020/10/eduardo-soares-LR0kDki_tPo-unsplash-scaled-e1603378645986-1400x568.jpg" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Tue, 22 Mar 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/fair-coin-from-biased-coin.html</guid></item><item><title>Read Browser File Inputs with Go WebAssembly</title><link>https://donatstudios.com/Read-User-Files-With-Go-WASM</link><description>&lt;p&gt;I have been &lt;a href="https://github.com/donatj/gojs"&gt;playing with WebAssembly&lt;/a&gt; since Go added support for it in 2017. &lt;/p&gt;
&lt;p&gt;For a very long time now, I've been wanting to be able to accept files from an end user and process them with Go on their local machine. Basically I just want to read files from &lt;em&gt;file inputs&lt;/em&gt;. I knew it had to be possible, but could not in all this time find a good walkthrough online. A couple nights ago I set my mind to it and figured it out.&lt;/p&gt;
&lt;p&gt;Essentially we need to execute the following JavaScript, but in Go via the JS syscall API.&lt;/p&gt;
 
&lt;p&gt;So after transliterating that JavaScript into Go &lt;code&gt;syscall/js&lt;/code&gt; calls, we then using &lt;code&gt;js.CopyBytesToGo&lt;/code&gt; to pass the given &lt;code&gt;Uint8Array&lt;/code&gt; back to our WASM runtime where we can do with the bytes as we please.&lt;/p&gt;
&lt;p&gt;Note, given the keyword &lt;code&gt;any&lt;/code&gt; here, this example requires Go 1.18 - the &lt;code&gt;syscall/js&lt;/code&gt; library is still considered experimental and expect it to break on major go releases.&lt;/p&gt;
 
&lt;p&gt;This is as written for brevity and could be improved in code safety in a number of pretty obvious ways.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;iframe&lt;/code&gt; below runs the compiled WASM and spits out any file you upload to it, via Go.&lt;/p&gt;
&lt;fieldset&gt;
&lt;legend&gt;Example&lt;/legend&gt;
 
&lt;/fieldset&gt;</description><author>Donat Studios</author><pubDate>Mon, 21 Mar 2022 05:11:42 GMT</pubDate><guid isPermaLink="true">https://donatstudios.com/Read-User-Files-With-Go-WASM</guid></item><item><title>2022–03–21: Some finer points about Alt-DP support in mainline kernel</title><link>https://xnux.eu/log/#063</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 21 Mar 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#063</guid></item><item><title>The Static File Startup</title><link>https://www.marginalia.nu/log/51-the-file-startup/</link><description>&lt;p&gt;Note: This is satirical in nature. Slight CW if you are at a point in life where &amp;ldquo;Office Space&amp;rdquo; has unveiled itself as a disturbing existential horror movie. This taps into that the same darkness.&lt;/p&gt;
&lt;p&gt;A tale of six brave Internet pioneers.&lt;/p&gt;
&lt;p&gt;Senior Business Founder / Senior CEO &amp;ndash; Zach
Senior Tech Lead / Senior Architect / Senior CTO &amp;ndash; Kevin
Senior Backend dev
Senior Frontend dev &amp;ndash; Erin
Two Senior UX engineers&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Fri, 18 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/51-the-file-startup/</guid></item><item><title>A Manifesto for the Metaverse</title><link>https://tiltingatwindmills.dev/a-manifesto-for-the-metaverse/</link><description>What is the Metaverse?
Wired tried to figure it
out recently and the results were inconclusive. Where is the metaverse? How do
we log in to…</description><author>Tilting at Windmills</author><pubDate>Thu, 17 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://tiltingatwindmills.dev/a-manifesto-for-the-metaverse/</guid></item><item><title>An excellent response, that didn't answer the question.</title><link>https://mikewarot.blogspot.com/2022/03/an-excellent-response-that-didnt-answer.html</link><description>&lt;p&gt;&amp;nbsp;&lt;a href="https://news.ycombinator.com/item?id=30666030"&gt;Ask HN&lt;/a&gt;: As you get older, do you see programming as merely a means to an end?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;38 points by amichail 18 hours ago | flag | hide | past | favorite | 45 comments&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;That is, you become more interested in what your app does rather than the programming involved to get it to do that?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;--- My Reply --- at &lt;a href="https://news.ycombinator.com/item?id=30674662"&gt;https://news.ycombinator.com/item?id=30674662&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Programming has gone through a weird path of effort/reward.&amp;nbsp; Initially, you had to invest time and a lot of money to build your own computer from a kit, debug any errors, and get to the point of having your own, personal computer. At that point, any working results were amazing, as there was a fair chance you were the first person to solve the given problem.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This lasted an amazingly long time. In the matter of less than a decade, the same amount of money, minus the time and effort of building and constructing, got you a computer, could be skipped. For the same amount of money, you got a computer with a display, floppy disks, and it just worked out of the box.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;DOS, BASIC, Turbo Pascal, Sidekick, PKzip, and so many tools game flooding in to make those computers even more easier to program, and productive.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;It was at THAT POINT, where I started really making money as a programmer.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;A decade passes, Windows 95 / Macintosh come along, and we get Visual Basic / Delphi / Hypercard.&amp;nbsp; WOW... the amount of effort goes up just a tiny bit, but you can do amazing things, and that code will run reliably for most of your users without much tweaking on the programmers part.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Then networking, the internet, SQL as a layer, Email, Microsoft Office, etc. all boost productivity for the users. The table stakes remain remarkably stable.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Then the iPhone comes along, and with a lot of effort, and the approval of Apple, you can build a program that people can carry around in their pockets. Apple decides to limit the retail price of apps, and bottleneck things through the App store.&amp;nbsp; Programming gets harder, and more specialized. Ugh&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Meanwhile, the web has grown popular, and the idea that a program should just work anywhere shatters the simplicity of a program running on a single computer,&amp;nbsp; directly talking to the OS that controls the display, and takes input. Again, programming gets harder, and more specialized.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Now we're at the point, where you're expected to make a program, sell it for less than a few dollars, support that program on any random phone, and hope that the two app stores don't arbitrarily change the rules and cut you off. The incentives go way up with audience size, and down with the giant filter of the app store.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;OR&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;To route around the damage of the App store, you are expected to make your program available on a server on the web, deal with hackers, man in the middle attacks, wildly varying desktop and mobile web browsers, bandwidth and legal restrictions, to deliver results to a user that might be at a desktop with multiple 4K screens on a gigabit internet... all the way to a person using an phone with no keyboard, who pays for data transfer, and might lose connection at any moment, might rotate the screen, and wants to interact with video, multiple cameras, gps, and any number of other sources of input or output.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;After all of that discourse to set perspective. Yes, I find it amazing that it can be done at all. I'm saddened that Delphi on Windows XP was probably the most productive GUI build environment I'll ever experience as a programmer.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;It's hard not to see the table stakes now as a huge barrier. For my own personal programs, it brings me joy every time something works. Every time I overcome a series of challenges, and my will becomes a tool... it amazes and overjoys me. I love programming. It's frustrating as hell, but I love it. I fail to see how anyone could stick with it if they didn't, at some level.&lt;/p&gt;</description><author>--Mike--</author><pubDate>Mon, 14 Mar 2022 21:43:05 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/03/an-excellent-response-that-didnt-answer.html</guid></item><item><title>A meditation on correctness in software</title><link>https://www.marginalia.nu/log/50-meditation-on-software-correctness/</link><description>&lt;p&gt;Let&amp;rsquo;s define a simple mathematical function, the function will perform integer factoring. It will take an integer, and return two integers, the product of which is the first integer.&lt;/p&gt;
&lt;p&gt;F(int32 n) = (int32 A, int32 B)&lt;/p&gt;
&lt;p&gt;so that&lt;/p&gt;
&lt;p&gt;A*B = n&lt;/p&gt;
&lt;p&gt;This is fairly straight forward, mathematical, objective. Let&amp;rsquo;s examine some answers an implementation might give.&lt;/p&gt;
&lt;p&gt;F 50 = (5, 10) on ARM
F 50 = (10, 5) on Intel&lt;/p&gt;
&lt;p&gt;This seems like a bug, so let&amp;rsquo;s add the requirement that A &amp;lt;= B for deterministic results.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Mon, 14 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/50-meditation-on-software-correctness/</guid></item><item><title>Could We Not Have Ideologies?</title><link>https://iamnotarobot.substack.com/p/could-we-not-have-ideologies</link><description>Ideology: &amp;#8220;a system of ideas and ideals, especially one which forms the basis of economic or political theory and policy.&amp;#8221;</description><author>I Am Not a Robot</author><pubDate>Sun, 13 Mar 2022 22:32:58 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/could-we-not-have-ideologies</guid></item><item><title>Detecting Badger2040 boards and automating uploads</title><link>http://blog.pythonaro.com/2022/03/detecting-badger2040-boards-and.html</link><description>&lt;p&gt;I recently bought a bunch of &lt;a href="https://shop.pimoroni.com/products/badger-2040" target="_blank"&gt;Pimoroni Badger2040&lt;/a&gt; boards, and they are a lot of fun.&lt;/p&gt;
&lt;p&gt;The Badger is basically a small microcontroller (the &lt;a href="https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html" target="_blank"&gt;Raspberry Pico&lt;/a&gt;) with an &lt;a href="https://en.wikipedia.org/wiki/E_Ink" target="_blank"&gt;eInk&lt;/a&gt; display, in the size of a typical office badge. It has a few buttons you can interact with, when powered, but because of eInk it doesn't actually need to be powered all the time - you can just set it to the desired screen, turn off the battery, and the screen will stay as it was more or less forever.&lt;/p&gt;
&lt;div class="separator" style="clear: both;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/a/AVvXsEhQjfsx9yvx5S3ZwufBblUw4f2s0RKSV4KFs6FW4uDXwIknQMsKLqpYrOfUaZAgDrDEh9qHUsW7qeydKdyERK5ewr4Jkrl8ovd_6AhmMmqN5Tws8y-4hmX81M7ArFP6z7-SLQEGjhjFpXB6bGptN6qGf6ZCbskvG_bs7xH3Gpc2--1P9HTr1w=s2799" style="display: block; padding: 1em 0; text-align: center;"&gt;&lt;img alt="" border="0" src="https://blogger.googleusercontent.com/img/a/AVvXsEhQjfsx9yvx5S3ZwufBblUw4f2s0RKSV4KFs6FW4uDXwIknQMsKLqpYrOfUaZAgDrDEh9qHUsW7qeydKdyERK5ewr4Jkrl8ovd_6AhmMmqN5Tws8y-4hmX81M7ArFP6z7-SLQEGjhjFpXB6bGptN6qGf6ZCbskvG_bs7xH3Gpc2--1P9HTr1w=s320" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The fun bit is that it can run &lt;a href="https://micropython.org/" target="_blank"&gt;MicroPython&lt;/a&gt;, so programming it is a breeze. You don't have to deal with all the scary vagaries of C/C++; just write your Python scripts, save them to the board, and run them. Sweet!&lt;/p&gt;
&lt;p&gt;There is already &lt;a href="https://learn.pimoroni.com/article/getting-started-with-badger-2040" target="_blank"&gt;a fairly comprehensive tutorial on how to get started with Badger2040&lt;/a&gt;, but (like most Pico-related documentation out there) it assumes you're happy to use &lt;a href="https://thonny.org/" target="_blank"&gt;Thonny&lt;/a&gt;, an editor focused on the micropython ecosystem, in order to move files to the board. With all due respect, Thonny is a very limited editor, and it gets recommended only because it's the most intuitive when it comes to managing files on the Pico. I'm much happier when I live in my beloved PyCharm, but its MicroPython plugin is somewhat limited and requires manual interaction, so I investigated a strategy to automate the basic stuff directly from Python on my laptop.&lt;/p&gt;
&lt;p&gt;The first step is detecting the board. It appears to the operating system as a serial port, so we have to list the available ports and find the one that looks like our guy.&lt;/p&gt;
&lt;pre&gt; # badgerutils.py
import serial.tools.list_ports as list_ports
from serial.tools.list_ports_common import ListPortInfo
  
def is_badger(port: ListPortInfo):
    """ decide if the port looks like a Badger2040 """
    # mac, but other systems will probably be similar,
    # just add other "if" blocks for windows etc
    if sys.platform.startswith('darwin'):
    	# you should be more thorough, 
        # might want to check VID etc, but this will do for dev
        if port.manufacturer and \
           	    port.manufacturer.lower().startswith('micropython'):
            return True
    return False
  
def get_badger():
    """ loop through all the ports and find our board """
    ports = list(list_ports.comports())
    for p in ports:
        if is_badger(p):
            return p
&lt;/pre&gt;
&lt;p&gt;The next step is where things get a bit hairy. Interacting over the serial port is not everyone's idea of fun, so we better stand on the shoulder of geeky giants if possible. We could dig through Thonny's code, but it's long and complicated and meant to support a lot of scenarios we don't really care about. Instead, we can reuse a little utility called &lt;a href="https://github.com/scientifichackers/ampy" target="_blank"&gt;ampy&lt;/a&gt;, which is slightly old but fairly robust and (more importantly) self-contained and easy to understand.&lt;/p&gt;
&lt;p&gt;Ampy includes a couple of modules to interact with a micropython board. You can have a look at the functions found in its &lt;code&gt;cli&lt;/code&gt; module to figure how to wrap them, but here's a simple approach to start pushing files to the board - some of the code is lifted almost entirely from &lt;a href="https://github.com/scientifichackers/ampy/blob/master/ampy/cli.py" target="_blank"&gt;ampy.cli&lt;/a&gt;, but it's MIT-licensed, so you can do that (just mention the original copyright notice somewhere, if you publish it!).&lt;/p&gt;
&lt;pre&gt;# BadgerManager.py
  
from serial.tools.list_ports_common import ListPortInfo
from ampy.files import Files, DirectoryExistsError
from ampy.pyboard import Pyboard
  
class MyBadger(Pyboard):

    def __init__(self, port: ListPortInfo):
        super(MyBadger, self).__init__(port.device)
        self.files = Files(self)

    def upload(self, file_path: Path, dest_path: Path):
        """ upload file or directory to board """
        if file_path.is_dir():
            # Directory copy, create the directory and walk all children 
            # to copy over the files. 
            for parent, child_dirs, child_files in os.walk(file_path):
                # Create board filesystem absolute path to parent directory.
                remote_parent = posixpath.normpath(
                    posixpath.join(dest_path, os.path.relpath(parent, file_path))
                )
                try:
                    # Create remote parent directory.
                    self.files.mkdir(remote_parent)
                except DirectoryExistsError:
                    # Ignore errors for directories that already exist.
                    pass
                # Loop through all the files and put them on the board too.
                for filename in child_files:
                    with open(os.path.join(parent, filename), "rb") as infile:
                        remote_filename = posixpath.join(remote_parent,
                                                         filename)
                        self.files.put(remote_filename, infile.read())
        else:
            # File copy
            # check if in subfolder
            if len(dest_path.parents) &gt; 1:
                # subfolder was specified
                # each parent has to be created individually,
                # because of ampy limitations
                for d in sorted(dest_path.parents)[1:]:  # first is /, discard
                    self.files.mkdir(d)

            # Put the file on the board.
            with open(file_path, "rb") as infile:
                self.files.put(dest_path.absolute(), infile.read())

    def ls(self, dirname='/', recurse=True):
        """ List files on board """
        dirpath = dirname if type(dirname) == Path else Path(dirname)
        return self.files.ls(dirpath.absolute(),
                             long_format=False, recursive=recurse)
&lt;/pre&gt;
&lt;p&gt;Putting both things together we can interact very easily with the board like this:&lt;/p&gt;
&lt;pre&gt;
from badgerutils import get_badger
from BadgerManager import MyBadger

# Note: in real life, remember to manage error conditions ! 
port = get_badger()
board = MyBadger(port)
board.upload("./something.txt", "/something.txt")
assert('/something.txt' in board.ls())
&lt;/pre&gt;
&lt;p&gt;Happy hacking!&lt;/p&gt;</description><author>Subclassed</author><pubDate>Sat, 12 Mar 2022 03:21:18 GMT</pubDate><guid isPermaLink="true">http://blog.pythonaro.com/2022/03/detecting-badger2040-boards-and.html</guid></item><item><title>The german tank problem in World War II</title><link>https://bytepawn.com/the-german-tank-problem-in-world-war-ii.html</link><description>&lt;p&gt;I run Monte Carlo simulations to show the frequntist solution to the German tank problem. &lt;br /&gt;&lt;br /&gt;&lt;img alt="." src="/images/german_tank_1.png" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 12 Mar 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/the-german-tank-problem-in-world-war-ii.html</guid></item><item><title>Here's what a "No Fly Zone" over Ukraine really means</title><link>https://mikewarot.blogspot.com/2022/03/heres-what-no-fly-zone-over-ukraine.html</link><description>&lt;div&gt;a "no fly" zone involves acquiring and maintaining air superiority over Ukraine and neighboring territory. To do this we would have to destroy any surface to air radar and missile sites in or near Ukraine. We would also have to shoot down any enemy aircraft that violated that airspace.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In sum total, it would be a declaration of war against Belarus and Russia.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It would then be up to Putin to decide if, where and when he wants to deploy the worlds largest stockpile of ThermoNuclear weapons.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Likely it would take about 15 minutes to confirm any launch, after which there might be a few minutes left to let the public know to make peace with God.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Your personal outcome at that point, depends on &lt;a href="https://www.youtube.com/watch?v=ox8ZDbCNTCE" target="_blank"&gt;preparation and luck&lt;/a&gt;:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A&amp;gt; You've felt the blast, and are going to die, maybe in seconds, maybe in days&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;B&amp;gt; You've seen the flash, and if you take cover soon enough, can survive the fallout, might survive and watch the total collapse of civilization.&lt;/div&gt;</description><author>--Mike--</author><pubDate>Fri, 11 Mar 2022 19:53:14 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/03/heres-what-no-fly-zone-over-ukraine.html</guid></item><item><title>The $100b Bull Case for Temporal</title><link>https://www.swyx.io/temporal-centicorn</link><description>&lt;p&gt;Why Temporal is worth &gt;$1b now, why it will be worth &gt;$10b, and how it &lt;em&gt;could&lt;/em&gt; be worth $100b&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Mon, 07 Mar 2022 19:21:34 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/temporal-centicorn</guid></item><item><title>Python is Like Assembly</title><link>https://specbranch.com/posts/python-and-asm/</link><description>&lt;p&gt;Python and Assembly have one thing in common: as a professional software engineer, they are both
languages that you probably should know how to read, but be terrified to write. These languages seem
to be (and are) at opposite ends of the spectrum: One is almost machine code, and the other is almost a
scripting language. One is beginner-friendly and the other is seen as hostile to experts. One is
viciously versatile with tons of libraries and ports, and the other is ridiculously limited in its
capabilities. However, when you are creating production software, both are the wrong tool for the
job.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Sun, 06 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/python-and-asm/</guid></item><item><title>Do Not Argue With Strangers on the Internet</title><link>https://iamnotarobot.substack.com/p/do-not-argue-with-strangers-on-the</link><description>Everyone knows that there are two kinds of superpowers: the useful and the shitty.</description><author>I Am Not a Robot</author><pubDate>Sat, 05 Mar 2022 18:56:53 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/do-not-argue-with-strangers-on-the</guid></item><item><title>Lessons From A Tech Job Search</title><link>https://nindalf.com/posts/tech-interview/</link><description>I share my experience and lessons learned from a recent tech job search, including tips on preparing for interviews and negotiating job offers.</description><author>Krishna's blog</author><pubDate>Sat, 05 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/tech-interview/</guid></item><item><title>Speeding up Go's builtin JSON encoder up to 55% for large arrays of objects</title><link>http://notes.eatonphil.com/improving-go-json-encoding-performance-for-large-arrays-of-objects.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-03-03-improving-go-json-encoding-performance-for-large-arrays-of-objects.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Thu, 03 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/improving-go-json-encoding-performance-for-large-arrays-of-objects.html</guid></item><item><title>Vim tip 5: jumping back and forth in Normal mode</title><link>https://learnbyexample.github.io/tips/vim-tip-5/</link><description>&lt;p&gt;Find yourself working on a large file? Or perhaps handling multiple buffers? Vim makes it easy to navigate previous locations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;o&lt;/kbd&gt; navigate to the previous location in the jump list (think &lt;code&gt;o&lt;/code&gt; as old)&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;i&lt;/kbd&gt; navigate to the next location in the jump list (&lt;code&gt;i&lt;/code&gt; and &lt;code&gt;o&lt;/code&gt; are usually next to each other)&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;g;&lt;/kbd&gt; go to the previous change location&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;g,&lt;/kbd&gt; go to the newer change location&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;gi&lt;/kbd&gt; place the cursor at the same position where it was left last time in the Insert mode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; Use &lt;kbd&gt;:jumps&lt;/kbd&gt; to view the jump list. See &lt;a href="https://vimhelp.org/motion.txt.html#jump-motions"&gt;:h jump-motions&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 02 Mar 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-5/</guid></item><item><title>How to Download Twitter Spaces That Aren't Yours</title><link>https://www.swyx.io/download-twitter-spaces</link><description>&lt;p&gt;Grabbing the audio&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Mon, 28 Feb 2022 22:14:56 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/download-twitter-spaces</guid></item><item><title>Marginalia Search: 1 year</title><link>https://www.marginalia.nu/log/49-marginalia-1-year/</link><description>&lt;p&gt;I&amp;rsquo;ve caught some bug and don&amp;rsquo;t have the energy to write more than a brief note.&lt;/p&gt;
&lt;p&gt;I want to commemorate the fact that work on the Marginalia search engine started one year ago. The first commit was on February 26th 2021, and contained a sketch for a website crawler and some data models.&lt;/p&gt;
&lt;p&gt;In many ways, the paint is barely dry, yet it feels like this project has been around for a long while.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Fri, 25 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/49-marginalia-1-year/</guid></item><item><title>Racing the Hardware: 8-bit Division</title><link>https://specbranch.com/posts/faster-div8/</link><description>&lt;p&gt;Occasionally, I like to peruse &lt;a href="https://uops.info"&gt;uops.info&lt;/a&gt;.  It is a great resource for micro-optimization:
benchmark every x86 instruction on every architecture, and compile the results.  Every time I look at this table,
there is one thing that sticks out to me: the &lt;code&gt;DIV&lt;/code&gt; instruction. On a Coffee Lake CPU, an 8-bit &lt;code&gt;DIV&lt;/code&gt; takes
a long time: 25 cycles.  Cannon Lake and Ice Lake do a lot better, and so does AMD. We know that divider
architecture is different between architectures, and aggregating all of the performance numbers for an
8-bit &lt;code&gt;DIV&lt;/code&gt;, we see:&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Tue, 22 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/faster-div8/</guid></item><item><title>2022–02–22: Adding LibreELEC.tv to an existing Pinephone multi-distro image</title><link>https://xnux.eu/log/#062</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 22 Feb 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#062</guid></item><item><title>2022–02–22: Pinephone Pro – Debugging Type C port issues</title><link>https://xnux.eu/log/#061</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 22 Feb 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#061</guid></item><item><title>I have no capslock and I must scream</title><link>https://www.marginalia.nu/log/48-i-have-no-capslock/</link><description>&lt;p&gt;In a near future, a team of desktop computer designers are looking at the latest telemetry and updating the schematics of the hardware-as-a-service self-assembling nanohardware.&lt;/p&gt;
&lt;p&gt;Steve: &amp;ldquo;Hmm, they don&amp;rsquo;t seem to be using the power button very often.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Bob: &amp;ldquo;Compared to the other buttons, it&amp;rsquo;s only used 0.1% of the time&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Steve: &amp;ldquo;Remove it?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Bob: &amp;ldquo;Remove it!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Computers now instantly boot up when plugged into the wall, and run until the plug is pulled. No more start-up time, the cases are aesthetically cleaner, and manufacturing cost is down at least a fraction of a dollar.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Mon, 21 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/48-i-have-no-capslock/</guid></item><item><title>SMTP protocol basics from scratch in Go: receiving email from Gmail</title><link>http://notes.eatonphil.com/handling-email-from-gmail-smtp-protocol-basics.html</link><description>&lt;p&gt;I've never run my own mail server before. Before today I had no clue
how email worked under the hood other than the very few times I've set
up mail clients.&lt;/p&gt;
&lt;p&gt;I've heard no few times how hard it is to &lt;em&gt;send&lt;/em&gt; mail from a
self-hosted server (because of spam filters). But how hard can it be
to hook up DNS to my personal server and receive email to my domain
sent from Gmail or another real-world client?&lt;/p&gt;
&lt;p&gt;I knew it would be simpler to just send local mail to a local mail
server with a local mail client but that didn't seem as real. If I
could send email from my Gmail account and receive it in my server I'd
be happy.&lt;/p&gt;
&lt;p&gt;I spent the afternoon digging into this. All code is &lt;a href="https://github.com/eatonphil/gomail"&gt;available on
Github&lt;/a&gt;. The "live stream" is in
the &lt;a href="https://discord.multiprocess.io"&gt;Multiprocess Discord&lt;/a&gt;'s
&amp;#35;hacking-networks channel.&lt;/p&gt;
&lt;h3 id="dns"&gt;DNS&lt;/h3&gt;&lt;p&gt;First I bought a domain. (I needed to be able to mess around with
records without blowing up anything important.)&lt;/p&gt;
&lt;p&gt;I knew that MX records controlled where mail for a domain is sent. But
I had to &lt;a href="https://en.wikipedia.org/wiki/MX_record"&gt;look up the
specifics&lt;/a&gt;. You need to
create an MX record that points to an A or AAAA record. So you need
both an MX record and an A or AAAA record.&lt;/p&gt;
&lt;p&gt;&lt;img alt="MX and A record settings" src="/dnsrecords.png" /&gt;&lt;/p&gt;
&lt;p&gt;Done.&lt;/p&gt;
&lt;h3 id="firewall"&gt;Firewall&lt;/h3&gt;&lt;p&gt;The firewall on Fedora is aggressive. Gotta open up port 25.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;firewall-cmd&lt;span class="w"&gt; &lt;/span&gt;--zone&lt;span class="o"&gt;=&lt;/span&gt;dmz&lt;span class="w"&gt; &lt;/span&gt;--add-port&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;/tcp&lt;span class="w"&gt; &lt;/span&gt;--permanent
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;firewall-cmd&lt;span class="w"&gt; &lt;/span&gt;--zone&lt;span class="o"&gt;=&lt;/span&gt;public&lt;span class="w"&gt; &lt;/span&gt;--add-port&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;/tcp&lt;span class="w"&gt; &lt;/span&gt;--permanent
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;firewall-cmd&lt;span class="w"&gt; &lt;/span&gt;--reload
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I don't understand what zones are here.&lt;/p&gt;
&lt;h3 id="what-protocols?"&gt;What protocols?&lt;/h3&gt;&lt;p&gt;I knew that you send email with SMTP and you read it with POP3 or
IMAP. But it hadn't clicked before that the mail server has to speak
SMTP and if you only ever read on the server (which is of course
impractical in the real world) you don't need POP3 or IMAP.&lt;/p&gt;
&lt;p&gt;&lt;img alt="SMTP vs POP3" src="https://cdn.educba.com/academy/wp-content/uploads/2019/07/smtp-protocol.png" /&gt;&lt;/p&gt;
&lt;p&gt;So to meaningfully receive email from Gmail all I needed to do was implement SMTP.&lt;/p&gt;
&lt;h3 id="smtp"&gt;SMTP&lt;/h3&gt;&lt;p&gt;First I found the &lt;a href="https://datatracker.ietf.org/doc/html/rfc5321"&gt;RFC for
SMTP&lt;/a&gt; (or one of them
anyway) and &lt;a href="https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol"&gt;the wikipedia page for
it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First off I'd need to run a TCP server on port 25.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;errors&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;net&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;strconv&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;strings&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[ERROR] %s\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[INFO] %s\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;clientDomain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;smtpCommands&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;atmHeaders&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Conn&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// TODO&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// TODO&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tcp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.0.0.0:25&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Listening&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just a basic TCP server that passes off connections inside a
goroutine.&lt;/p&gt;
&lt;h3 id="greeting"&gt;Greeting&lt;/h3&gt;&lt;p&gt;After starting a connection, the server must send a greeting. The
successful greeting response code is &lt;code&gt;220&lt;/code&gt;. It can optionally be
followed by additional text. Like most commands in SMTP it must be
ended with CRLF (&lt;code&gt;\r\n&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;So we'll add a helper function for writing lines that end in CRLF:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;writeLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\r\n&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then we'll send that &lt;code&gt;220&lt;/code&gt; in the &lt;code&gt;handle&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Connection accepted&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;220&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Awaiting EHLO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// TODO&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="ehlo"&gt;EHLO&lt;/h3&gt;&lt;p&gt;Next we need to be able to read requests from the client. We'll write
a helper that reads until the next CRLF. We'll keep a buffer of unread
bytes in case we accidentally get bytes past the next CRLF. We'll
store that buffer in the connection object.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// If end of line&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\r'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;// i-1 because drop the CRLF, no one cares after this&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now back in the &lt;code&gt;handle&lt;/code&gt;-er we can read a line from the client. From
the RFC we can see it should be &lt;code&gt;HELO&lt;/code&gt; or &lt;code&gt;EHLO&lt;/code&gt;. Both sendmail locally
and Gmail only send &lt;code&gt;EHLO&lt;/code&gt; though so we'll just check for that.&lt;/p&gt;
&lt;p&gt;&lt;img alt="EHLO response format" src="/ehloresponse.png" /&gt;&lt;/p&gt;
&lt;p&gt;So we'll validate the message sent is an &lt;code&gt;EHLO&lt;/code&gt; and then we'll send
back a &lt;code&gt;250&lt;/code&gt; with a space after it. We can ignore the rest of that
response grammar since we don't have additional keywords we want to
send to the client.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;Awaiting EHLO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;EHLO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;Expected EHLO got: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nl"&gt;smtpCommands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="err"&gt;{}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nl"&gt;atmHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="err"&gt;{}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clientDomain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;len(&amp;quot;EHLO &amp;quot;):&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;Received EHLO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;250 &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;Done EHLO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TODO&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="additional-commands"&gt;Additional commands&lt;/h3&gt;&lt;p&gt;Next up there are a few commands we need to read before we get to the
message body. These include the recipient and the sender
address. These are formatted vaguely similar to HTTP headers. They
have a key on the left side of a colon and a value on the right. They
may have a required order too, I'm not sure.&lt;/p&gt;
&lt;p&gt;In response to the commands we'll send a &lt;code&gt;250 OK&lt;/code&gt;, although I'm not
sure where in the RFC that is suggested.&lt;/p&gt;
&lt;p&gt;In our code we'll just keep looking for these commands until we find
the &lt;code&gt;DATA&lt;/code&gt; command. This indicates the body is to follow. And to this
command we respond with a &lt;code&gt;354&lt;/code&gt; instead of a &lt;code&gt;250 OK&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="DATA response" src="/dataresponse.png" /&gt;&lt;/p&gt;
&lt;p&gt;In code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Done EHLO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;pieces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SplitN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;smtpCommand&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pieces&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// Special command without a value&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;smtpCommand&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DATA&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;354&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;smtpValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pieces&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;smtpCommands&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;smtpCommand&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;smtpValue&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Got command: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;250 OK&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Done SMTP commands, reading ARPA text message headers&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// TODO&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="message-body,-headers"&gt;Message body, headers&lt;/h3&gt;&lt;p&gt;Now that we've seen the &lt;code&gt;DATA&lt;/code&gt; command we are within &lt;em&gt;a&lt;/em&gt; message
body. Within this body we still have to read some additional headers.&lt;/p&gt;
&lt;p&gt;Through trial-and-error I know to look for some headers like
&lt;code&gt;Subject&lt;/code&gt;. By searching the RFC I noticed a reference to &lt;a href="https://datatracker.ietf.org/doc/html/rfc822"&gt;RFC
822&lt;/a&gt; where these headers
are defined.&lt;/p&gt;
&lt;p&gt;&lt;img alt="ARPA text message headers" src="/subject.png" /&gt;&lt;/p&gt;
&lt;p&gt;These are ARPA internet text message headers apparently. They also
look like HTTP headers but unlike HTTP headers they can span multiple
lines. This stumped me for a bit.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Multi-line headers" src="/longheaders.png" /&gt;&lt;/p&gt;
&lt;p&gt;I decided to write a new &lt;code&gt;readLine&lt;/code&gt; function that would specifically
look for these possibly multi-line headers where a CRLF followed by
whitespace isn't a line delimiter.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readMultiLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;noMoreReads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\t'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\r'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;// i-2 because drop the CRLF, no one cares after this&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;noMoreReads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isBodyClose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;noMoreReads&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;// If this gets here more than once it's going to be an infinite loop&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;isBodyClose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\r'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'.'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\r'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now back in the &lt;code&gt;handle&lt;/code&gt; function we can read through all of these
headers. According to RFC 822, we're done when we see a double CRLF,
which in our code will show up as an empty line.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Done SMTP headers, reading ARPA text message headers&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readMultiLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TrimSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;pieces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SplitN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;atmHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pieces&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;atmValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pieces&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;atmHeaders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;atmHeader&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmValue&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SUBJECT&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmValue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;TO&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmValue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;FROM&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmValue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DATE&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;atmValue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Done ARPA text message headers, reading body&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// TODO&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="body,-for-real"&gt;Body, for real&lt;/h3&gt;&lt;p&gt;We're finally at the email body as the user typed it. According to the
SMTP RFC the body ends with a CRLF followed by a dot (period) followed
by a CRLF.&lt;/p&gt;
&lt;p&gt;So we'll write another helper to read until this marker.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readToEndOfBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isBodyClose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we can finish up the &lt;code&gt;handle&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Done ARPA text message headers, reading body&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readToEndOfBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Got body (%d bytes)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;250 OK&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Message:\n%s\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Connection closed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="compile,-setcap,-run,-and-send"&gt;Compile, setcap, run, and send&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;setcap&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'cap_net_bind_service=+ep'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./gomail
$&lt;span class="w"&gt; &lt;/span&gt;./gomail
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And send an email in Gmail! It can be to any user since we haven't
implemented anything regarding users. I'll send &lt;code&gt;What hath god
wrought&lt;/code&gt; as the subject and message to &lt;code&gt;morse@binutils.org&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And I see:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:17:19&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Listening
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Connection&lt;span class="w"&gt; &lt;/span&gt;accepted
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Awaiting&lt;span class="w"&gt; &lt;/span&gt;EHLO
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Received&lt;span class="w"&gt; &lt;/span&gt;EHLO
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Done&lt;span class="w"&gt; &lt;/span&gt;EHLO
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Got&lt;span class="w"&gt; &lt;/span&gt;header:&lt;span class="w"&gt; &lt;/span&gt;MAIL&lt;span class="w"&gt; &lt;/span&gt;FROM:&amp;lt;me@eatonphil.com&amp;gt;
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Got&lt;span class="w"&gt; &lt;/span&gt;header:&lt;span class="w"&gt; &lt;/span&gt;RCPT&lt;span class="w"&gt; &lt;/span&gt;TO:&amp;lt;morse@binutils.org&amp;gt;
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Done&lt;span class="w"&gt; &lt;/span&gt;SMTP&lt;span class="w"&gt; &lt;/span&gt;headers,&lt;span class="w"&gt; &lt;/span&gt;reading&lt;span class="w"&gt; &lt;/span&gt;ARPA&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="w"&gt; &lt;/span&gt;message&lt;span class="w"&gt; &lt;/span&gt;headers
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Done&lt;span class="w"&gt; &lt;/span&gt;ARPA&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="w"&gt; &lt;/span&gt;message&lt;span class="w"&gt; &lt;/span&gt;headers,&lt;span class="w"&gt; &lt;/span&gt;reading&lt;span class="w"&gt; &lt;/span&gt;body
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Got&lt;span class="w"&gt; &lt;/span&gt;body&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;256&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Message:
--000000000000c4758905d87ddb81
Content-Type:&lt;span class="w"&gt; &lt;/span&gt;text/plain&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;

What&lt;span class="w"&gt; &lt;/span&gt;hath&lt;span class="w"&gt; &lt;/span&gt;god&lt;span class="w"&gt; &lt;/span&gt;wrought

--000000000000c4758905d87ddb81
Content-Type:&lt;span class="w"&gt; &lt;/span&gt;text/html&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;

&amp;lt;div&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ltr&amp;quot;&lt;/span&gt;&amp;gt;What&lt;span class="w"&gt; &lt;/span&gt;hath&lt;span class="w"&gt; &lt;/span&gt;god&lt;span class="w"&gt; &lt;/span&gt;wrought&amp;lt;/div&amp;gt;

--000000000000c4758905d87ddb81--

&lt;span class="m"&gt;2022&lt;/span&gt;/02/21&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;02&lt;/span&gt;:19:13&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;209&lt;/span&gt;.85.222.47:40695&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Connection&lt;span class="w"&gt; &lt;/span&gt;closed
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is pretty sweet!&lt;/p&gt;
&lt;h3 id="multipart-wut"&gt;Multipart wut&lt;/h3&gt;&lt;p&gt;Ok this body still clearly has some format. And if we dump the ARPA
text message headers we notice that Gmail 1) sets a Content-Type
header and 2) it's value is &lt;code&gt;multipart/alternative&lt;/code&gt;. I don't know
where Content-Type as a valid header is defined because it's not in
RFC 822. Maybe it's some "new-fangled" adhoc standard or maybe it's
just in an extension RFC.&lt;/p&gt;
&lt;p&gt;In any case this looks like multipart bodies in HTTP. I don't want to
deal with that so I'm just going to stop here.&lt;/p&gt;
&lt;p&gt;But I &lt;em&gt;am&lt;/em&gt; curious about text-only email systems. So I &lt;code&gt;sudo dnf
install php sendmail&lt;/code&gt; and write a quick PHP script (thanks to @Josh on
Discord for the suggestion):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
  &lt;span class="nb"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;morse@binutils.org&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;What hath god wrought&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;What hath god wrought&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And run it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;php&lt;span class="w"&gt; &lt;/span&gt;test.php
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And in my &lt;code&gt;gomail&lt;/code&gt; window I see:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Listening&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;accepted&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Awaiting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EHLO&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Received&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EHLO&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EHLO&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Got&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAIL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;phil&lt;/span&gt;&lt;span class="nv"&gt;@dev1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eatonphil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Got&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RCPT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;morse&lt;/span&gt;&lt;span class="nv"&gt;@binutils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SMTP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ARPA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ARPA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Got&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;What&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;god&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wrought&lt;/span&gt;

&lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1: 127.0.0.1:45102&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;closed&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And I'm happy to call it a night.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I wrote a new blog post on building an SMTP server from scratch in Go that is correctly enough hooked up you can receive emails sent from Gmail to it!&lt;br /&gt;&lt;br /&gt;Good fun and some learning too.&lt;a href="https://t.co/8pYkkAbFnI"&gt;https://t.co/8pYkkAbFnI&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1495586245896028160?ref_src=twsrc%5Etfw"&gt;February 21, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;
&lt;p&gt;p.s. if you want to see more networking software/hardware internals
check out
&lt;a href="https://reddit.com/r/networkdevelopment"&gt;/r/NetworkDevelopment&lt;/a&gt;.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 20 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/handling-email-from-gmail-smtp-protocol-basics.html</guid></item><item><title>Drive Failure</title><link>https://www.marginalia.nu/log/47-drive-failure/</link><description>&lt;p&gt;Not what I had intended to do this Saturday, but a hard drive failed on the server this morning, or at least so it seemed. MariaDB server went down, dmesg was full of error messages for the nvme drive it&amp;rsquo;s running off. That&amp;rsquo;s a pretty important drive.&lt;/p&gt;
&lt;p&gt;The drive itself may actually be okay, the working hypothesis is either the drive itself or the bus overheated and reset. After a reboot the system seems fine.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Sat, 19 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/47-drive-failure/</guid></item><item><title>In response to Doc's story of the Story</title><link>https://mikewarot.blogspot.com/2022/02/in-response-to-docs-story-of-story.html</link><description>&lt;p&gt;Doc Searls was at it again back in 2018 doing a &lt;a href="https://tedxsantabarbara.com/2018/doc-searls/?fbclid=IwAR2JLbVdgLJgOxxUPPf1QoLLW6pvp-905guW1opbk9NlFX-QLwPIBcxmCbI" target="_blank"&gt;Ted Talk&lt;/a&gt;. His story rhymes with his overall message, and the things he wrote back then. I think it's time to examine how events have evolved since then.&lt;br /&gt;&lt;br /&gt;*This story is me revising and extending my &lt;a href="http://doc.blog/2020/02/01/theLostCenter.html" rel="nofollow" target="_blank"&gt;reply&lt;/a&gt; on Facebook. (It's buried in the comments, don't bother)&lt;br /&gt;&lt;br /&gt;Doc worried about the &lt;a href="http://doc.blog/2020/02/01/theLostCenter.html" target="_blank"&gt;lost center&lt;/a&gt;&amp;nbsp;in coverage of the news, and overall discussion. I too feel the loss. There's an old saying, "The Net treats Censorship as Damage, and routes around it". I think that it takes time in the world of atoms, but that John Gilmore was right.&lt;br /&gt;&lt;br /&gt;Communications, Data Storage, and Compute infrastructure have grown exponentially with the commercialized internet. The physical costs of producing and sharing content have fallen to almost zero. It's not perfect, and there are some left out, but for the most part anyone can be online, and have a say in the world.&lt;br /&gt;&lt;br /&gt;In response to the visible failure of advertising driven funding, crowd funding now is filling in the missing channel of support to keep those who wish to share on the internet going. A number of new journalists are arising. Some of them cover things traditionally called news. It's not perfect, and there are bits of censorship creeping in around the edges, but it is working.&lt;br /&gt;&lt;br /&gt;For me, my most trusted news sources at the moment are spread across YouTube. It makes it possible for me to give authority to my choices, make them my authoritative sources. I'm filling in that lost center with the people who I think can best tell me what I need to know, and why others tell the stories they do.&lt;br /&gt;&lt;br /&gt;Now, having a centrist view does make discussions with those entrained in the left/right thought bubbles frustrating at times, but who knows, maybe we'll all pull the center back together?&lt;br /&gt;&lt;br /&gt;Here's how I approach news gathering in 2022.&lt;br /&gt;&lt;br /&gt;I'd heard from the mainstream that leaks in via friends that there was a ruckus brewing over Ukraine. For this story, most trusted sources were Beau of the Fifth Column, Breaking Points with Krystal and Sagaar, and Robb Law.&lt;br /&gt;&lt;br /&gt;To be really sure, I stuck with first hand imaging via a list of live webcams across Ukraine. It was fairly easy to be certain no invasion was feared by the locals as they went about skiing in Ivano-Frankivsk, walking across Sophia Square in Kiev, or Pysanka museum (also in Ivano-Frankivsk).&lt;/p&gt;&lt;p&gt;For practical advice, matters of instruction, the future is really here. You can learn all manner of technical facts and skills. There are some limitations I've noticed, for instance one channel on machining had a really great multi-part series on the intricacies of making a part of a fyre arm, which he was forced to remove. I have no desire to actually do that, but there were a number of creative methods used, like using a quill of a milling machine as a vertical broach, and this was an outstanding example of why you would do it. That knowledge is now walled off, and considered tainted by association.&lt;/p&gt;&lt;p&gt;I've long stated that our computers aren't safe because of a design flaw at their core. I now believe that this censorious tendency in the chain of payment is a similar danger.&lt;/p&gt;&lt;p&gt;It remains to be seen how we'll route around it.&lt;/p&gt;</description><author>--Mike--</author><pubDate>Fri, 18 Feb 2022 20:42:40 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/02/in-response-to-docs-story-of-story.html</guid></item><item><title>You Think You Consume Information. What if the Opposite Is True?</title><link>https://iamnotarobot.substack.com/p/you-think-you-consume-information</link><description>In 1981, an Italian six-year-old boy named Alfredo Rampi fell into a well.</description><author>I Am Not a Robot</author><pubDate>Thu, 17 Feb 2022 00:18:46 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/you-think-you-consume-information</guid></item><item><title>Unabridged Conclusion to the State of JS</title><link>https://www.swyx.io/state-of-js-2021</link><description>&lt;p&gt;the full text of my State of JS writeup!&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Wed, 16 Feb 2022 14:04:45 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/state-of-js-2021</guid></item><item><title>Let's choose a better timeline</title><link>https://mikewarot.blogspot.com/2022/02/lets-choose-better-timeline.html</link><description>&lt;p&gt;&amp;nbsp;I believe in this causal chain,&lt;/p&gt;&lt;p style="text-align: left;"&gt;&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Computers are insecure&lt;/li&gt;&lt;li&gt;Which many bad actors find profit in exploiting&lt;/li&gt;&lt;li&gt;Which makes new web sites a risk&lt;/li&gt;&lt;li&gt;Which makes users prefer their known "safe" spaces&lt;/li&gt;&lt;li&gt;Which leads to walled gardens&lt;/li&gt;&lt;li&gt;Which then sell the "users" for profit to advertisers&lt;/li&gt;&lt;li&gt;Which incentivizes dark behavior of those walled gardens&lt;/li&gt;&lt;li&gt;Which then attract the rentier class&lt;/li&gt;&lt;li&gt;Which then leverage control for more power&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;I believe this causal chain can be broken by fixing computer security. The necessary research was done in the 1970s. The Bell-Lapadula model [1] in 1973 was one of the significant results.&lt;/p&gt;&lt;p&gt;The Principle of Least Privilege [2] was adopted in the Unix system in a weak form. The superuser (root) account was a special privilege, which administrators and code was supposed to use as little as possible.&lt;/p&gt;&lt;p&gt;There were (are???) implementations of a multi-level secure systems, which saw limited application in the military, and briefly elsewhere. However, for general use, the root/user separation was widely seen as good enough.&lt;/p&gt;&lt;p&gt;There are now efforts to fully extend operating systems so that they can provide tools so that the users can also use the Principle of Least Privilege. I believe that eventually it will be as easy to use these as more conventional systems.&lt;/p&gt;&lt;p&gt;In these systems, no default permissions are given when running a program, the allowed resources, also known as capabilities, must be specified. This is similar to deciding which bank notes you are going to hand to a cashier, instead of handing over your wallet. It is up to US to demand that it be as easy for any user to do so, in a transparent way.&lt;/p&gt;&lt;p&gt;It is my hope, that should this model be accepted, a new causal chain will arise&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Computers will be made secure&lt;/li&gt;&lt;li&gt;Which users will grow to trust&lt;/li&gt;&lt;li&gt;Which will allow experimentation&lt;/li&gt;&lt;li&gt;Which allows new ways of communicating&lt;/li&gt;&lt;li&gt;Which don't require corporate sponsorship&lt;/li&gt;&lt;li&gt;Which doesn't require the rentier class&lt;/li&gt;&lt;li&gt;Which helps innovation&lt;/li&gt;&lt;li&gt;Which helps society&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;1 -&amp;nbsp; https://web.archive.org/web/20060618092351/http://www.albany.edu/acc/courses/ia/classics/belllapadula1.pdf&lt;/p&gt;&lt;p&gt;2 - https://en.wikipedia.org/wiki/Principle_of_least_privilege&lt;/p&gt;</description><author>--Mike--</author><pubDate>Sun, 13 Feb 2022 18:56:39 GMT</pubDate><guid isPermaLink="true">https://mikewarot.blogspot.com/2022/02/lets-choose-better-timeline.html</guid></item><item><title>The Meaning of Speed</title><link>https://specbranch.com/posts/performance-dimensions/</link><description>&lt;p&gt;A lot of the time, when engineers think of performance work, we think about looking at benchmarks and
making the numbers smaller.  We anticipate that we are benchmarking the right pieces of code, and we take
it for granted that reducing some of those numbers is a benefit, but also &amp;quot;the root of all evil&amp;quot; if done
prematurely.  If you are a performance-focused software engineer, or you are working with performance
engineers, it can help to understand the value proposition of performance and when to work on it.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Sun, 13 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/performance-dimensions/</guid></item><item><title>Delightfully cynical half-truths about organizations</title><link>https://bytepawn.com/delightfully-cynical-half-truths-about-organizations.html</link><description>&lt;p&gt;Five delightfully cynical half-truths about organizations: the Peter principle, the Dilbert principle, the Gervais principle, Negative selection and the Dunning-Kruger effect. &lt;br /&gt;&lt;br /&gt;&lt;img alt="." src="/images/dilbert1.jpg" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 12 Feb 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/delightfully-cynical-half-truths-about-organizations.html</guid></item><item><title>A Job Pays Much More Than a Salary</title><link>https://iamnotarobot.substack.com/p/a-job-pays-much-more-than-a-salary</link><description>When comparing two job offers, the first thought that comes to my mind is, what is the difference in pay?</description><author>I Am Not a Robot</author><pubDate>Fri, 11 Feb 2022 20:52:38 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/a-job-pays-much-more-than-a-salary</guid></item><item><title>Full-disk encryption on Slackware, the modern way</title><link>http://localhost:4000/2022/02/10/slackware-crypt-efi-only.html</link><description/><author>RyNo’s Site</author><pubDate>Thu, 10 Feb 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">http://localhost:4000/2022/02/10/slackware-crypt-efi-only.html</guid></item><item><title>The McClusky Curve - Viral vs Evergreen Content</title><link>https://www.swyx.io/mcclusky-curve</link><description>&lt;p&gt;An insightful discussion on how to trade off aiming for viral or permanent posts.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Thu, 10 Feb 2022 08:31:50 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/mcclusky-curve</guid></item><item><title>The Most Incompetent Person I Ever Worked With</title><link>https://boyter.org/posts/most-incompetent-person-worked-with/</link><description>&lt;p&gt;Previously I had covered the &lt;a href="https://boyter.org/2014/02/worst-program-worked/"&gt;worst program&lt;/a&gt; I had ever worked on (although that probably needs updating now) and the &lt;a href="https://boyter.org/2016/08/worst-individual-worked/"&gt;worst individual&lt;/a&gt;. I thought it was time branch out into the most incompetent person I ever worked with.&lt;/p&gt;
&lt;p&gt;So a bit of back history. This was at lendlease where we were working on a system that massaged all employee data into a single place allowing accurate counts of employees, and getting titles mapped to real ones and such. This was important because lendlease being an umbrella style company had gobbled up lots of other ones and so nobody had a clue how many people actually worked for it.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Thu, 10 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/most-incompetent-person-worked-with/</guid></item><item><title>Rust in 2024</title><link>https://nindalf.com/posts/rust-future/</link><description>I predict the state of Rust programming language in 2024, highlighting areas of improvement and making predictions on various aspects of the language.</description><author>Krishna's blog</author><pubDate>Thu, 10 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/rust-future/</guid></item><item><title>Vim tip 4: reposition current line in Normal mode</title><link>https://learnbyexample.github.io/tips/vim-tip-4/</link><description>&lt;p&gt;You're likely to be familiar with commands to scroll through the contents like &lt;kbd&gt;Ctrl&lt;/kbd&gt; followed by &lt;kbd&gt;d&lt;/kbd&gt; or &lt;kbd&gt;f&lt;/kbd&gt; or &lt;kbd&gt;u&lt;/kbd&gt; or &lt;kbd&gt;b&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;Did you know that Vim also has handy options to keep the cursor on the current line while moving the contents around?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;zz&lt;/kbd&gt; reposition the current line to the middle of the visible window
&lt;ul&gt;
&lt;li&gt;useful to see context around lines that are nearer to the top/bottom of the visible window&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;zt&lt;/kbd&gt; reposition the current line to the top of the visible window&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;zb&lt;/kbd&gt; reposition the current line to the bottom of the visible window&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/options.txt.html#%27scrolloff%27"&gt;:h 'scrolloff'&lt;/a&gt; option if you want to always show context around the current line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 09 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-4/</guid></item><item><title>The world of PostgreSQL wire compatibility</title><link>http://notes.eatonphil.com/the-world-of-postgresql-wire-compatibility.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-02-08-the-world-of-postgresql-wire-compatibility.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Tue, 08 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/the-world-of-postgresql-wire-compatibility.html</guid></item><item><title>Slackware 15.0 on the Framework</title><link>http://localhost:4000/2022/02/07/slackware-on-framework.html</link><description/><author>RyNo’s Site</author><pubDate>Mon, 07 Feb 2022 10:00:00 GMT</pubDate><guid isPermaLink="true">http://localhost:4000/2022/02/07/slackware-on-framework.html</guid></item><item><title>The Anatomy of Search Engine Spam</title><link>https://www.marginalia.nu/log/46-anatomy-of-search-engine-spam/</link><description>&lt;p&gt;Black hat SEO is endlessly fascinating phenomenon to study. This post is about some tactics they use to make their sites rank higher.&lt;/p&gt;
&lt;p&gt;The goal of blackhat SEO is to boost the search engine ranking of a page nobody particularly wants to see, usually ePharma, escort services, online casinos, shitcoins, hotel bookings; the bermuda pentagon of shady websites.&lt;/p&gt;
&lt;p&gt;The theory behind most modern search engines is that if you get links from a high ranking domain, then your domain gets a higher ranking as well, which increases the traffic. The reality is a little more complicated than that, but this is a sufficient mental model to understand the basic how-to.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Mon, 07 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/46-anatomy-of-search-engine-spam/</guid></item><item><title>Moving to a GitHub CMS</title><link>https://www.swyx.io/github-cms</link><description>&lt;p&gt;Discussing the 2022 migration of swyx.io to SvelteKit and GitHub Issues&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sun, 06 Feb 2022 22:50:11 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/github-cms</guid></item><item><title>Moving to Obsidian as a Public Second Brain</title><link>https://www.swyx.io/obsidian-brain</link><description>&lt;p&gt;The case for having a -Public- Second Brain, and why I picked Obsidian.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Sun, 06 Feb 2022 20:08:26 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/obsidian-brain</guid></item><item><title>Michael Keaton is Underappreciated</title><link>https://tiltingatwindmills.dev/michael-keaton-is-underappreciated/</link><description>Two things. Michael Keaton starred in the film Birdman or (The Unexpected Virtue of Ignorance) in 2014. Three years later in 2017 he played…</description><author>Tilting at Windmills</author><pubDate>Sat, 05 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://tiltingatwindmills.dev/michael-keaton-is-underappreciated/</guid></item><item><title>How to add JSDoc Typechecking to SvelteKit</title><link>https://www.swyx.io/jsdoc-swyxkit</link><description>&lt;p&gt;As I build out swyxkit, I am finding that I am no longer prototyping and that I need to be able to refactor with confidence.&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Fri, 04 Feb 2022 12:22:01 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/jsdoc-swyxkit</guid></item><item><title>Can we unfuck internet discoverability?</title><link>https://www.marginalia.nu/log/45-unfuck-internet-discoverability/</link><description>&lt;p&gt;I&amp;rsquo;ve been thinking a lot about how difficult it has become to discover quality content on the Internet, not because it isn&amp;rsquo;t there, but because the signal to noise ratio is really bad, and most venues of discovery don&amp;rsquo;t seem to be able to handle it.&lt;/p&gt;
&lt;p&gt;Recommendation algorithms seem to work almost too well, to the point where it&amp;rsquo;s all kind of just showing you things you already like, rarely anything new that you might like. It&amp;rsquo;s an absolute tragedy both for small websites and for their potential audience.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Fri, 04 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/45-unfuck-internet-discoverability/</guid></item><item><title>Installing voice2json on Ubuntu</title><link>https://boyter.org/posts/installing-voice2json-ubuntu/</link><description>&lt;p&gt;I have been playing around with offline non cloud tool replacements for doing things like speech to text and the like. One that I found which looked promising was voice2json which is a command line tool for turning speech intent into text. It can do generic conversion too, but a review of that is not the subject of this post.&lt;/p&gt;
&lt;p&gt;Following the instructions from the website &lt;a href="http://voice2json.org/install.html"&gt;http://voice2json.org/install.html&lt;/a&gt; worked fine up till I tried to run it and got the following issue.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Thu, 03 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/installing-voice2json-ubuntu/</guid></item><item><title>Reason Is a Sword, Not a Swiss Army Knife</title><link>https://iamnotarobot.substack.com/p/reason-is-a-sword-not-a-swiss-army</link><description>Why smart people sometimes do dumb things</description><author>I Am Not a Robot</author><pubDate>Wed, 02 Feb 2022 02:52:40 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/reason-is-a-sword-not-a-swiss-army</guid></item><item><title>PyDev of the Week</title><link>https://learnbyexample.github.io/mini/pydev-interview/</link><description>&lt;p&gt;Last month I had the wonderful opportunity to be part of &lt;a href="https://www.blog.pythonlibrary.org/category/pydevoftheweek/"&gt;PyDev of the Week&lt;/a&gt; series organized by &lt;strong&gt;Michael Driscoll&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It was a pleasure to walk down the memory lane for this interview: &lt;a href="https://www.blog.pythonlibrary.org/2022/01/31/pydev-of-the-week-sundeep-agarwal/"&gt;https://www.blog.pythonlibrary.org/2022/01/31/pydev-of-the-week-sundeep-agarwal/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I got to discuss about my education, career, writing ebooks and more. Hope you enjoy the interview!&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Wed, 02 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/mini/pydev-interview/</guid></item><item><title>Resurrecting Bogan Ipsum</title><link>https://boyter.org/posts/resurrecting-bogan-ipsum/</link><description>&lt;p&gt;I remember hearing about Bogan Ipsum, which was an alternative to Lorem Ipsum for you know bogan&amp;rsquo;s back in 2011 through &lt;a href="https://www.lifehacker.com.au/2011/09/strewth-bogan-ipsum-gives-you-aussie-filler-text/"&gt;LifeHacker&lt;/a&gt;. However it since became defunct. I became aware of this fact from Darren at work given the following message on slack?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dude&lt;/p&gt;
&lt;p&gt;Boganipsum where?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Clearly this needed to be rectified! A quick search found this &lt;a href="https://www.npmjs.com/package/boganipsum"&gt;https://www.npmjs.com/package/boganipsum&lt;/a&gt; implementation which seemed to work well enough, so I ported it to basic JavaScript (think 2001 style JavaScript) and threw together a quick HTML page. I then registered &lt;a href="https://boganipsum.com.au/"&gt;https://boganipsum.com.au/&lt;/a&gt; and the result?&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Tue, 01 Feb 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/resurrecting-bogan-ipsum/</guid></item><item><title>2022–02–01: Pinephone Pro – Type C port support</title><link>https://xnux.eu/log/#060</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 01 Feb 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#060</guid></item><item><title>Performance Numbers Worth Knowing</title><link>https://specbranch.com/posts/common-perf-numbers/</link><description>&lt;p&gt;When you design software to achieve a particular level of performance, it can be a good idea to be familiar with
the general speed regimes you are working with: fundamental limitations like storage devices and networks can drive
software architecture. Here are a set of common benchmark numbers that can help you anchor performance conversations
and think about the components that your software will interact with. As with all guidelines, these numbers are all
slightly wrong, but still useful.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Mon, 31 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/common-perf-numbers/</guid></item><item><title>How to recommend books, or, stop recommending SICP</title><link>http://notes.eatonphil.com/recommending-a-book.html</link><description>&lt;p&gt;Many "must-read" books are not well-written. I &lt;a href="https://www.goodreads.com/user/show/50930981-phil-eaton"&gt;try to read a
lot&lt;/a&gt;, but I
still have a low tolerance for bad writing and bad editing. I write
this post both to discourage thoughtless recommendations and to
encourage the receivers of bad recommendations.&lt;/p&gt;
&lt;p&gt;For software developers, Structure and Interpretation of Computer
Programs is a prime example. Written for freshman at MIT, it is
ostensibly an entry-level text. But it requires such a level of
competence in math and physics, and the prose itself is so dense and
archaic, that I couldn't imagine suggesting it to anyone.&lt;/p&gt;
&lt;p&gt;And yet it is one of the most recommended books for developers.&lt;/p&gt;
&lt;p&gt;This is not to say that SICP is a bad book or that you should not read
it. I just don't think it should ever be suggested to anyone.&lt;/p&gt;
&lt;h3 id="goal"&gt;Goal&lt;/h3&gt;&lt;p&gt;The core goal of a book recommendation is for the reader to get
enjoyment or education from it. If you can't continue or finish a
book, you get nothing from it.&lt;/p&gt;
&lt;p&gt;You, the recommender, diminish your impact if you can only recommend
books that people won't continue or finish.&lt;/p&gt;
&lt;h4 id="non-goal"&gt;Non-goal&lt;/h4&gt;&lt;p&gt;Some people have the capacity to read and love challenging books. If
that is you, you are not the audience of this post. I don't think
you'd disagree that most people are not like you.&lt;/p&gt;
&lt;h3 id="why"&gt;Why&lt;/h3&gt;&lt;p&gt;I have a few, not-mutually-exclusive guesses why "must-read" books are
often poorly written.&lt;/p&gt;
&lt;p&gt;One guess is intelligence signalling. That it is human nature for a
person to suggest a book in an attempt make herself look smart rather
than to best assist the person asking for a suggestion.&lt;/p&gt;
&lt;p&gt;Another guess is that most people don't read enough to have a good
feel for better or worse writing and editing.&lt;/p&gt;
&lt;p&gt;And a final guess is that books that are worth reading might not
always be well-written. This is the most unfortunate guess of all. I
don't disagree that sometimes it is necessary to learn from
poorly-written books. But I begrudge this because of how much joy I
get from reading well-written books, fiction and non-fiction.&lt;/p&gt;
&lt;p&gt;I have a feeling my guesses apply to recommendations in
general: music, art, film, musicals, restaurants, etc.&lt;/p&gt;
&lt;h3 id="instead"&gt;Instead&lt;/h3&gt;&lt;p&gt;My suggestion then to folks who are in the position of giving
recommendations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you had a hard time reading a book or it took you too long to read it (yes, this threshold is different for everyone), don't recommend it&lt;/li&gt;
&lt;li&gt;Don't be scared to recommend nothing, or to recommend against (rather than for) a certain book&lt;/li&gt;
&lt;li&gt;Read more books&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And definitely don't recommend books you haven't read.&lt;/p&gt;
&lt;h3 id="mea-culpa"&gt;Mea culpa&lt;/h3&gt;&lt;p&gt;I've definitely done a bad job recommending books in the past,
including recommending books I haven't read. I've been trying to do
better in the last 5 years or so.&lt;/p&gt;
&lt;p&gt;What do you think?&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I wrote a new blog post: a bit of flame bait on how to recommend books and why so many must-read books are impossible to read.&lt;br /&gt;&lt;br /&gt;Or: stop recommending SICP.&lt;br /&gt;&lt;br /&gt;If you love challenging books, you are neither the norm nor the audience of this post. 😀&lt;a href="https://t.co/ZU92kgr4Kf"&gt;https://t.co/ZU92kgr4Kf&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1488204810541219840?ref_src=twsrc%5Etfw"&gt;January 31, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Mon, 31 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/recommending-a-book.html</guid></item><item><title>2022–01–31: Pinephone Pro battery charging</title><link>https://xnux.eu/log/#059</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 31 Jan 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#059</guid></item><item><title>Probabilistic spin glass - Conclusion</title><link>https://bytepawn.com/probabilistic-spin-glass-conclusion.html</link><description>&lt;p&gt;I summarize the 5 previous posts on probabilistic spin glasses. &lt;br /&gt;&lt;br /&gt;&lt;img alt="." src="/images/prob_spin_glass_21.png" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Mon, 31 Jan 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/probabilistic-spin-glass-conclusion.html</guid></item><item><title>CVE-2022-0329 and the problems with automated vulnerability management</title><link>https://tomforb.es/blog/cve-2022-0329-and-the-problems-with-automated-vulnerability-management/</link><description>Update: Github have responded and said they will stop sending notifications about this CVE. Yesterday Github started notifying tens of thousands of people about a critical remote code execution vulnerability in a package named loguru. Their reviewed advisory is here. It references CVE-2022-0329 whic...</description><author>Tom Forbes</author><pubDate>Sat, 29 Jan 2022 19:25:09 GMT</pubDate><guid isPermaLink="true">https://tomforb.es/blog/cve-2022-0329-and-the-problems-with-automated-vulnerability-management/</guid></item><item><title>Rust has a small standard library (and that's ok)</title><link>https://nindalf.com/posts/rust-stdlib/</link><description>This article explores the reasons why Rust has a small standard library and why it's okay.</description><author>Krishna's blog</author><pubDate>Sat, 29 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/rust-stdlib/</guid></item><item><title>The Swyx.io 2022 Rewrite</title><link>https://www.swyx.io/rewrite-2022</link><description>&lt;p&gt;Discussing the 2022 migration of swyx.io to SvelteKit and GitHub Issues&lt;/p&gt;</description><author>swyx's site RSS Feed</author><pubDate>Thu, 27 Jan 2022 09:53:45 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/rewrite-2022</guid></item><item><title>What if Global Warming Is Good for You?</title><link>https://iamnotarobot.substack.com/p/what-if-global-warming-is-good-for</link><description>No, We Are Not All in It Together</description><author>I Am Not a Robot</author><pubDate>Wed, 26 Jan 2022 22:49:26 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/what-if-global-warming-is-good-for</guid></item><item><title>Bootloader basics</title><link>http://notes.eatonphil.com/bootloader-basics.html</link><description>&lt;p&gt;I spent a few days playing around with bootloaders for the first
time. This post builds up to a text editor with a few keyboard
shortcuts. I'll be giving a virtual talk based on this work at &lt;a href="https://www.meetup.com/hackernights/"&gt;Hacker
Nights on Jan 27&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are a definitely bugs. But it's hard to find intermediate
resources for bootloader programming so maybe parts of this will be
useful.&lt;/p&gt;
&lt;p&gt;If you already know the basics and the intermediates and just want a
fantastic intermediate+ tutorial, maybe try
&lt;a href="https://0x00sec.org/t/realmode-assembly-writing-bootable-stuff-part-5/3667"&gt;this&lt;/a&gt;. It
is very good.&lt;/p&gt;
&lt;p&gt;The code on this post is available on
&lt;a href="https://github.com/eatonphil/bootloaders"&gt;Github&lt;/a&gt;, but it's more of a
mess than my usual project.&lt;/p&gt;
&lt;h3 id="motivation:-snake"&gt;Motivation: Snake&lt;/h3&gt;&lt;p&gt;You remember &lt;a href="https://www.quaxio.com/bootloader_retro_game_tweet/"&gt;snake bootloader in a
tweet&lt;/a&gt; from a few
years ago?&lt;/p&gt;
&lt;p&gt;Install qemu (on macOS or Linux), nasm, and copy the &lt;code&gt;snake.asm&lt;/code&gt;
source code to disk from that blog post.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;snake.asm&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="k"&gt;bits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;; Pragma, tells the assembler that we&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="c1"&gt;; are in 16 bit mode (which is the state&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="c1"&gt;; of x86 when booting from a floppy).&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7C00&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;; Pragma, tell the assembler where the&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="c1"&gt;; code will be loaded.&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;; Starting direction for the worm.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xa000&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;; Load address of VRAM into es.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;es&lt;/span&gt;

&lt;span class="nl"&gt;restart_game:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;si&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; worm's starting position, center of&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="c1"&gt;; screen&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Set video mode. Mode 13h is VGA (1 byte per pixel with the actual&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; color stored in a palette), 320x200 total size. When restarting,&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; this also clears the screen.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0013&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Draw borders. We assume the default palette will work for us.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; We also assume that starting at the bottom and drawing 2176 pixels&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; wraps around and ends up drawing the top + bottom borders.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;di&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;199&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2176&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;rep&lt;/span&gt;
&lt;span class="nl"&gt;draw_loop:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;stosb&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; draw right border&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;stosb&lt;/span&gt;&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="c1"&gt;; draw left border&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;di&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;318&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;jnc&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;draw_loop&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; notice the jump in the middle of the&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="c1"&gt;; rep stosb instruction.&lt;/span&gt;

&lt;span class="nl"&gt;game_loop:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; We read the keyboard input from port 0x60. This also reads bytes from&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; the mouse, so we need to only handle [up (0x48), left (0x4b),&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; right (0x4d), down (0x50)]&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;in&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x60&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x48&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;jb&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;kb_handle_end&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x50&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;ja&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;kb_handle_end&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; At the end bx contains offset displacement (+1, -1, +320, -320)&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; based on pressed/released keypad key. I bet there are a few bytes&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; to shave around here given the bounds check above.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;aaa&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;cbw&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;jc&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;kb_handle&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;imul&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x50&lt;/span&gt;
&lt;span class="nl"&gt;kb_handle:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;bx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;

&lt;span class="nl"&gt;kb_handle_end:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;si&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bx&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; The original code used set pallete command (10h/0bh) to wait for&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; the vertical retrace. Today's computers are however too fast, so&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; we use int 15h 86h instead. This also shaves a few bytes.&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Note: you'll have to tweak cx+dx if you are running this on a virtual&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; machine vs real hardware. Casual testing seems to show that virtual machines&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; wait ~3-4x longer than physical hardware.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x86&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nb"&gt;dh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xef&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="mh"&gt;0x15&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Draw worm and check for collision with parity&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; (even parity=collision).&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x45&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;es&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;si&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; Go back to the main game loop.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;jpo&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;game_loop&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;; We hit a wall or the worm. Restart the game.&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;restart_game&lt;/span&gt;

&lt;span class="kd"&gt;TIMES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;; Fill the rest of sector with 0&lt;/span&gt;
&lt;span class="kd"&gt;dw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xaa55&lt;/span&gt;&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="c1"&gt;; Boot signature at the end of bootloader&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;nasm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;bin&lt;span class="w"&gt; &lt;/span&gt;snake.asm&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;snake.bin
$&lt;span class="w"&gt; &lt;/span&gt;qemu-system-x86_64&lt;span class="w"&gt; &lt;/span&gt;-fda&lt;span class="w"&gt; &lt;/span&gt;snake.bin
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt="Recording of snake bootloader" src="bootloader-basics-snake.gif" /&gt;&lt;/p&gt;
&lt;p&gt;What a phenomenal hack.&lt;/p&gt;
&lt;p&gt;I'm not going to get anywhere near that level of sophistication in
this post but I think it's great motivation.&lt;/p&gt;
&lt;h3 id="hello-world"&gt;Hello world&lt;/h3&gt;&lt;p&gt;Bootloaders are a mix of assembly programming and BIOS APIs for
I/O. Since you're thinking about bootloaders you already know assembly
basics. Now all you have to do is learn the APIs.&lt;/p&gt;
&lt;p&gt;The hello world bootloader has been explained in detail (see
&lt;a href="https://github.com/briansteffens/briansteffens.github.io/blob/master/blog/hello-world-from-a-bootloader/post.md"&gt;here&lt;/a&gt;,
&lt;a href="https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/writing-a-custom-bootloader"&gt;here&lt;/a&gt;,
and &lt;a href="http://3zanders.co.uk/2017/10/13/writing-a-bootloader/"&gt;here&lt;/a&gt;) so
I won't go into too much line-by-line depth.&lt;/p&gt;
&lt;p&gt;In fact, let's just pull the code from the latter blog post.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hello.asm&lt;/span&gt;
&lt;span class="k"&gt;bits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; tell NASM this is 16 bit code&lt;/span&gt;
&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7c00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; tell NASM to start outputting stuff at offset 0x7c00&lt;/span&gt;
&lt;span class="nl"&gt;boot:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;si&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;hello&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; point si register to hello label memory location&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;0x0e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; 0x0e means 'Write Character in TTY mode'&lt;/span&gt;
&lt;span class="nl"&gt;.loop:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;lodsb&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; is al == 0 ?&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;halt&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; if (al == 0) jump to halt label&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; runs BIOS interrupt 0x10 - Video Services&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.loop&lt;/span&gt;
&lt;span class="nl"&gt;halt:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;cli&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; clear interrupt flag&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;hlt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; halt execution&lt;/span&gt;
&lt;span class="nl"&gt;hello:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hello world!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="kd"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kc"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; pad remaining 510 bytes with zeroes&lt;/span&gt;
&lt;span class="kd"&gt;dw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xaa55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; magic bootloader magic - marks this 512 byte sector bootable!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The computer boots, prints "Hello world!" and hangs.&lt;/p&gt;
&lt;p&gt;But aside from clerical settings (16-bit assembly, where the program
exists in memory, padding to 512 bytes) the only real bootloader-y
magic in there is &lt;code&gt;int 0x10&lt;/code&gt;, a BIOS interrupt.&lt;/p&gt;
&lt;h4 id="bios-interrupts-=-api-calls-for-i/o"&gt;BIOS interrupts = API calls for I/O&lt;/h4&gt;&lt;p&gt;BIOS interrupts are API calls. Just like syscalls in userland programs
they have a specific register convention and number to call for the
family of APIs.&lt;/p&gt;
&lt;p&gt;When you write bootloader programs you'll spend most of your time at
first trying to understand the behavior of the various BIOS APIs.&lt;/p&gt;
&lt;p&gt;The two families we'll deal with in this post are the keyboard family
(documentation &lt;a href="https://stanislavs.org/helppc/int_16.html"&gt;here&lt;/a&gt;) and
the display family (documentation
&lt;a href="https://stanislavs.org/helppc/int_10.html"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h4 id="run-hello-world"&gt;Run hello world&lt;/h4&gt;&lt;p&gt;Anyway, back to the hello world. Assemble it with nasm and run it with
qemu.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;nasm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;bin&lt;span class="w"&gt; &lt;/span&gt;hello.asm&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;hello.bin
$&lt;span class="w"&gt; &lt;/span&gt;qemu-system-x86_64&lt;span class="w"&gt; &lt;/span&gt;-fda&lt;span class="w"&gt; &lt;/span&gt;hello.bin
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt="Printing hello world" src="bootloader-basics-hello.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Getting the hang of it?&lt;/p&gt;
&lt;h3 id="io-loop"&gt;IO Loop&lt;/h3&gt;&lt;p&gt;The specific function we called above to write a character to the
display is &lt;a href="https://stanislavs.org/helppc/int_10-e.html"&gt;INT
10,E&lt;/a&gt;. The &lt;code&gt;0x10&lt;/code&gt;
is the argument that you call the &lt;code&gt;int&lt;/code&gt; keyword with
(e.g. &lt;code&gt;int 0x10&lt;/code&gt;). And the &lt;code&gt;E&lt;/code&gt; is the specific
function within the &lt;code&gt;0x10&lt;/code&gt; family. The &lt;code&gt;E&lt;/code&gt; is
written into the &lt;code&gt;AH&lt;/code&gt; register before
calling &lt;code&gt;int&lt;/code&gt;. The ASCII code to be written is placed in
the &lt;code&gt;AL&lt;/code&gt; register.&lt;/p&gt;
&lt;p&gt;Now that output makes some sense, let's do input. In the &lt;a href="https://stanislavs.org/helppc/int_16.html"&gt;keyboard services
documentation&lt;/a&gt; you may
notice that &lt;a href="https://stanislavs.org/helppc/int_16-0.html"&gt;INT 16,0&lt;/a&gt;
provides a way to block for user input. According to that page the
ASCII character will be in &lt;code&gt;AL&lt;/code&gt; when the interrupt returns.&lt;/p&gt;
&lt;h4 id="clearing-the-screen"&gt;Clearing the screen&lt;/h4&gt;&lt;p&gt;You may have noticed some text gets displayed before our program
runs. We can use &lt;a href="https://stanislavs.org/helppc/int_10-0.html"&gt;INT
0x10,0&lt;/a&gt; to clear the
screen.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;        ;; Clear screen
        mov ah, 0x00
        mov al, 0x03
        int 0x10
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="all-together"&gt;All together&lt;/h4&gt;&lt;p&gt;Since the display function reads from the same register the input
function outputs to, we can just call both interrupts after each
other. Wrap this in a loop and we have the world's worst editor.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ioloop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asm&lt;/span&gt;
&lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;
&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7c00&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Clear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;screen&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;

&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;character&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x16&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;character&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0e&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;

&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;$-$$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zeroes&lt;/span&gt;
&lt;span class="n"&gt;dw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xaa55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bootloader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;marks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sector&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bootable&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  By the way, the &lt;code&gt;main&lt;/code&gt; label here (like
  the &lt;code&gt;boot&lt;/code&gt; label above in &lt;code&gt;hello.asm&lt;/code&gt;) is only
  to help the reader. It is not something the BIOS uses.
&lt;/p&gt;&lt;p&gt;Now that we've got the code, let's run it!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;nasm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;bin&lt;span class="w"&gt; &lt;/span&gt;ioloop.asm&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;ioloop.bin
$&lt;span class="w"&gt; &lt;/span&gt;qemu-system-x86_64&lt;span class="w"&gt; &lt;/span&gt;-fda&lt;span class="w"&gt; &lt;/span&gt;ioloop.bin
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt="Recording of ioloop bootloader" src="bootloader-basics-ioloop.gif" /&gt;&lt;/p&gt;
&lt;h3 id="digression-on-abstraction"&gt;Digression on abstraction&lt;/h3&gt;&lt;p&gt;There are two ways to build abstractions: assembly functions and nasm
macros.&lt;/p&gt;
&lt;p&gt;We could build a clear screen function like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nl"&gt;clear_screen:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Clear screen&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then we can call this in the ioloop program like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;bits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;
&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7c00&lt;/span&gt;

&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;

&lt;span class="nl"&gt;clear_screen:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Clear screen&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;

&lt;span class="nl"&gt;main:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;clear_screen&lt;/span&gt;

&lt;span class="nl"&gt;.loop:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Read character&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x16&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Print character&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0e&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.loop&lt;/span&gt;

&lt;span class="kd"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kc"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; pad remaining 510 bytes with zeroes&lt;/span&gt;
&lt;span class="kd"&gt;dw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xaa55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; magic bootloader magic - marks this 512 byte sector bootable!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On the other hand if you do it in a macro:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;bits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;
&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7c00&lt;/span&gt;

&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;

&lt;span class="cp"&gt;%macro cls 0 &lt;/span&gt;&lt;span class="c1"&gt;; Zero is the number of arguments&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;

&lt;span class="nl"&gt;main:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;cls&lt;/span&gt;

&lt;span class="nl"&gt;.loop:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Read character&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x16&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Print character&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0e&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.loop&lt;/span&gt;

&lt;span class="kd"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kc"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; pad remaining 510 bytes with zeroes&lt;/span&gt;
&lt;span class="kd"&gt;dw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xaa55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; magic bootloader magic - marks this 512 byte sector bootable!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And nasm macros even have a way to write macro-safe labels by
prefixing them with &lt;code&gt;%%&lt;/code&gt; which is useful if you have
conditions or loops within a macro.&lt;/p&gt;
&lt;p&gt;The benefit of a macro I guess is that you're not using up the
stack. The benefit of a function call is that you're not duplicating
code every place you use a macro. The amount of generated code
eventually becomes important in bootloaders because the code must
fit into 512 bytes.&lt;/p&gt;
&lt;p&gt;I lean more toward using macros in this code.&lt;/p&gt;
&lt;h3 id="complex-input"&gt;Complex input&lt;/h3&gt;&lt;p&gt;Reading ASCII characters is not complicated as we saw above. But what
if we want to build Readline style shortcuts like ctrl-a for jumping
to the start of the line?&lt;/p&gt;
&lt;p&gt;Using INT 16,0 as we do above is fine. But rather than solely reading
from the result of that function call, there is a section of memory
that contains both the character pressed and control characters
pressed.&lt;/p&gt;
&lt;p&gt;Based on documentation for this memory area (found
&lt;a href="http://www.techhelpmanual.com/93-rom_bios_variables.html"&gt;here&lt;/a&gt; or
&lt;a href="https://www.tau.ac.il/~flaxer/edu/course/processcontrol/BiosDataArea.pdf"&gt;here&lt;/a&gt;),
we can build a macro for reading the pressed character:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;%macro mov_read_character_into 1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x041a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03fe&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Offset from 0x0400 - sizeof(uint16) (since head points to next free slot, not last/current slot)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xFFFF&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xFF&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And another macro for reading the pressed control character (if any):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;%macro mov_read_ctrl_flag_into 1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x0417&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x04&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Grab 3rd bit: %1 &amp;amp; 0b0100&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="cursor-location"&gt;Cursor location&lt;/h3&gt;&lt;p&gt;Lastly we'll use some cursor APIs that allow us to handle
newlines, backspace on the first column of a line, and ctrl-a (jump to
beginning of line).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;%macro get_position 0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;

&lt;span class="cp"&gt;%macro set_position 0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x02&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But there's something buggy about my &lt;code&gt;goto_end_of_line&lt;/code&gt;
function. Sometimes it works and sometimes it just jumps all over the
screen in an infinite loop. Part of the problem is that the editor
memory is the video card. The cursor location is only stored there and
not in some program state like you might do in a high-level
environment/language.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nl"&gt;goto_end_of_line:&lt;/span&gt;
&lt;span class="c1"&gt;;; Get current character&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x08&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;

&lt;span class="c1"&gt;;; Iterate until the character is null&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dl&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;set_position&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goto_end_of_line&lt;/span&gt;

&lt;span class="nl"&gt;.done:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Alright, let's put all these pieces together.&lt;/p&gt;
&lt;h3 id="editor-with-keyboard-shortcuts"&gt;Editor with keyboard shortcuts&lt;/h3&gt;&lt;p&gt;Start with the basics in &lt;code&gt;editor.asm&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;; -*- mode: nasm;-*-&lt;/span&gt;

&lt;span class="k"&gt;bits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;
&lt;span class="k"&gt;org&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7c00&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then add a clear screen macro.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;%macro cls 0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x00&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Add macros for reading and printing.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;%macro read_character 0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;;; Read character&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x16&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;

&lt;span class="cp"&gt;%macro print_character 1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0e&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Add cursor utilities.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;%macro get_position 0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;

&lt;span class="cp"&gt;%macro set_position 0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x02&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;

&lt;span class="nl"&gt;goto_end_of_line:&lt;/span&gt;
&lt;span class="c1"&gt;;; Get current character&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x08&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;

&lt;span class="c1"&gt;;; Iterate until the character is null&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dl&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;set_position&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goto_end_of_line&lt;/span&gt;

&lt;span class="nl"&gt;.done:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And keyboard utilities.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;%macro mov_read_ctrl_flag_into 1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x0417&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x04&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Grab 3rd bit: %1 &amp;amp; 0b0100&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;

&lt;span class="cp"&gt;%macro mov_read_character_into 1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0x041a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x03fe&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;; Offset from 0x0400 - sizeof(uint16) (since head points to next free slot, not last/current slot)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xFFFF&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xFF&lt;/span&gt;
&lt;span class="cp"&gt;%endmacro&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can start the editor loop where we wait for a keypress and
handle it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nl"&gt;editor_action:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;read_character&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Don't print ASCII garbage if the key pressed is an arrow key. Just do
nothing. (This isn't good editor behavior in general but ours is a
limited one.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;;; Ignore arrow keys&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x4b&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Left&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x50&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Down&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x4d&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Right&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x48&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; Up&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next handle backspace.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;;; Handle backspace&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x08&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.is_backspace&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x7F&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;; For mac keyboards&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jnz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done_backspace&lt;/span&gt;

&lt;span class="nl"&gt;.is_backspace:&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;get_position&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If this key is pressed at the first line and the first column, do
nothing.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;;; Handle 0,0 coordinate (do nothing)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dh&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dl&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.overwrite_character&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Otherwise if backspace is pressed not at the beginning of the line,
just overwrite the last character with the ASCII 0 (the code 0 not the
digit 0).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.backspace_at_start_of_line&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dl&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Decrement column&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;set_position&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.overwrite_character&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Otherwise you're at the beginning of the line and you need to jump to
the end of the previous line.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nl"&gt;.backspace_at_start_of_line:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dh&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Decrement row&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;set_position&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goto_end_of_line&lt;/span&gt;

&lt;span class="nl"&gt;.overwrite_character:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ah&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0a&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x10&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;

&lt;span class="nl"&gt;.done_backspace:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we handle the Enter key. This should move the cursor onto the
next line and set the column back to zero.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;;; Handle enter&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov_read_character_into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0d&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jnz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done_enter&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;get_position&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dh&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;; Increment line&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; Reset column&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;set_position&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;

&lt;span class="nl"&gt;.done_enter:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we handle ctrl-a, jump to start of line.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;;; Handle ctrl- shortcuts&lt;/span&gt;

&lt;span class="c1"&gt;;; Check ctrl key&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov_read_ctrl_flag_into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.ctrl_not_set&lt;/span&gt;

&lt;span class="c1"&gt;;; Handle ctrl-a shortcut&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov_read_character_into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;; For some reason with ctlr, these are offset from a-z&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jnz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.not_ctrl_a&lt;/span&gt;

&lt;span class="c1"&gt;;; Reset column&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;set_position&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;

&lt;span class="nl"&gt;.not_ctrl_a:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For ctrl-e, jump to the end of the line.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;;; Handle ctrl-e shortcut&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov_read_character_into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jnz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.not_ctrl_e&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goto_end_of_line&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;

&lt;span class="nl"&gt;.not_ctrl_e:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.done&lt;/span&gt;

&lt;span class="nl"&gt;.ctrl_not_set:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally if none of these cases are met, just print the pressed character and return.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;mov_read_character_into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;print_character&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ax&lt;/span&gt;

&lt;span class="nl"&gt;.done:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;ret&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, create the main function that calls this editor code in a loop.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nl"&gt;main:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;cls&lt;/span&gt;

&lt;span class="nl"&gt;.loop:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;editor_action&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;jmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;.loop&lt;/span&gt;

&lt;span class="kd"&gt;times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;510&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kc"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; pad remaining 510 bytes with zeroes&lt;/span&gt;
&lt;span class="kd"&gt;dw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xaa55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; magic bootloader magic - marks this 512 byte sector bootable!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we're done! Try it out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;nasm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;bin&lt;span class="w"&gt; &lt;/span&gt;editor.asm&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;editor.bin
$&lt;span class="w"&gt; &lt;/span&gt;qemu-system-x86_64&lt;span class="w"&gt; &lt;/span&gt;-fda&lt;span class="w"&gt; &lt;/span&gt;editor.bin
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt="Recording of a bad editor" src="bootloader-basics-editor.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Tedious and buggy! But I learned something, I think.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I wrote a new post on my first time exploring bootloader basics! Neat to discover the BIOS APIs and spend some time actually coding in assembly versus just generating or emulating it.&lt;a href="https://t.co/7iP6Nib620"&gt;https://t.co/7iP6Nib620&lt;/a&gt; &lt;a href="https://t.co/xSyG1IXgEB"&gt;pic.twitter.com/xSyG1IXgEB&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1485398216124346371?ref_src=twsrc%5Etfw"&gt;January 23, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 23 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/bootloader-basics.html</guid></item><item><title>Constant-time Fibonacci</title><link>https://specbranch.com/posts/const-fib/</link><description>&lt;p&gt;This is the second part in a 2-part series on the &amp;quot;Fibonacci&amp;quot; interview problem.
We are building off of a previous post, so &lt;a href="https://specbranch.com/posts/fibonacci/"&gt;take a look at Part I&lt;/a&gt; if you haven't seen it.&lt;/p&gt;
&lt;p&gt;Previously, we examined the problem and constructed a logarithmic-time solution based on computing the power
of a matrix.  Now we will derive a constant time solution using some more linear algebra. If you had
trouble with the linear algebra in part I, it may help to read up on
&lt;a href="https://www.mathsisfun.com/algebra/matrix-introduction.html"&gt;matrices&lt;/a&gt;,
&lt;a href="https://www.mathsisfun.com/algebra/matrix-multiplying.html"&gt;matrix multiplicaiton&lt;/a&gt;, and special matrix
operations (specifically &lt;a href="https://www.mathsisfun.com/algebra/matrix-determinant.html"&gt;determinants&lt;/a&gt;
and &lt;a href="https://www.mathsisfun.com/algebra/matrix-inverse.html"&gt;inverses&lt;/a&gt;) before moving on.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Sat, 22 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/const-fib/</guid></item><item><title>2022–01–22: Pinephone Keyboard – kernel driver merged</title><link>https://xnux.eu/log/#058</link><author>megi's PinePhone Development Log</author><pubDate>Sat, 22 Jan 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#058</guid></item><item><title>Optimal coverage for Wordle with Monte Carlo methods - Part III</title><link>https://bytepawn.com/optimal-coverage-for-wordle-with-monte-carlo-methods-part-iii.html</link><description>&lt;p&gt;I present a simple Monte Carlo solution which finds a 25-letter-unique Worlde wordlist in about 10 minutes. &lt;br /&gt;&lt;br /&gt;&lt;img alt="Wordle" src="/images/wordle_3.PNG" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 22 Jan 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/optimal-coverage-for-wordle-with-monte-carlo-methods-part-iii.html</guid></item><item><title>Optimal coverage for Wordle with Monte Carlo methods - Part II</title><link>https://bytepawn.com/optimal-coverage-for-wordle-with-monte-carlo-methods-part-ii.html</link><description>&lt;p&gt;I improve on the previous brute-force Monte Carlo approach for attacking the Wordle coverage problem. &lt;br /&gt;&lt;br /&gt;&lt;img alt="Wordle" src="/images/wordle_2.PNG" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 21 Jan 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/optimal-coverage-for-wordle-with-monte-carlo-methods-part-ii.html</guid></item><item><title>Science Is Not Something You Listen To</title><link>https://iamnotarobot.substack.com/p/science-is-not-something-you-listen</link><description>Over the past couple of years, &amp;#8220;listen to science&amp;#8221; has been present in countless tweets and media soundbites.</description><author>I Am Not a Robot</author><pubDate>Wed, 19 Jan 2022 19:39:32 GMT</pubDate><guid isPermaLink="true">https://iamnotarobot.substack.com/p/science-is-not-something-you-listen</guid></item><item><title>Optimal coverage for Wordle with Monte Carlo methods - Part I</title><link>https://bytepawn.com/optimal-coverage-for-wordle-with-monte-carlo-methods.html</link><description>&lt;p&gt;I show a simple brute-force Monte Carlo approach for attacking the Wordle coverage problem. &lt;br /&gt;&lt;br /&gt;&lt;img alt="Wordle" src="/images/wordle_1.PNG" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Wed, 19 Jan 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/optimal-coverage-for-wordle-with-monte-carlo-methods.html</guid></item><item><title>Discovery and Design Considerations</title><link>https://www.marginalia.nu/log/44-discovery-and-design/</link><description>&lt;p&gt;It&amp;rsquo;s been a productive several weeks. I&amp;rsquo;ve got the feature pulling updates from RSS working, as mentioned earlier.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve spent the last weeks designing the search engine&amp;rsquo;s web design, and did the MEMEX too for good measure.&lt;/p&gt;
&lt;p&gt;It needed to be done as the blog theme that previously made the foundation for the design off had several problems, including loading a bunch of unnecessary fonts, and not using the screen space of desktop browsers well at all.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Tue, 18 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/44-discovery-and-design/</guid></item><item><title>Fix a Pothole</title><link>https://tiltingatwindmills.dev/fix-a-pothole/</link><description>The goal of media is to make every problem, your problem. — Naval Ravikant Today we hear about every problem around the world as it happens…</description><author>Tilting at Windmills</author><pubDate>Tue, 18 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://tiltingatwindmills.dev/fix-a-pothole/</guid></item><item><title>Vim tip 3: autocomplete words and lines in Insert mode</title><link>https://learnbyexample.github.io/tips/vim-tip-3/</link><description>&lt;p&gt;&lt;strong&gt;Autocomplete word&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;p&lt;/kbd&gt; autocomplete word based on matching words in the backward direction&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;n&lt;/kbd&gt; autocomplete word based on matching words in the forward direction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; If more than one word matches, they are displayed using a popup menu. You can use &lt;kbd&gt;↑&lt;/kbd&gt;/&lt;kbd&gt;↓&lt;/kbd&gt; arrow keys or &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;p&lt;/kbd&gt;/&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;n&lt;/kbd&gt; to move through this list.&lt;/p&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; With multiple matches, you'll notice that the first match is automatically inserted and moving through the list doesn't change the text that was inserted. You'll have to press &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;y&lt;/kbd&gt; or &lt;kbd&gt;Enter&lt;/kbd&gt; key to choose a different completion text. If you were satisfied with the first match, typing any character will make the popup menu disappear and insert whatever character you had typed. Or press &lt;kbd&gt;Esc&lt;/kbd&gt; to select the first match and go to Normal mode.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Autocomplete line&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;x&lt;/kbd&gt; followed by &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;l&lt;/kbd&gt; autocomplete line based on matching lines in the backward direction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; If more than one line matches, they are displayed using a popup menu. You can use &lt;kbd&gt;↑&lt;/kbd&gt;/&lt;kbd&gt;↓&lt;/kbd&gt; arrow keys or &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;p&lt;/kbd&gt;/&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;n&lt;/kbd&gt; to move through this list. You can also use &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;l&lt;/kbd&gt; to move up the list.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Autocomplete assist&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;e&lt;/kbd&gt; cancels autocomplete
&lt;ul&gt;
&lt;li&gt;you'll retain the text you had typed before invoking autocomplete&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;y&lt;/kbd&gt; or &lt;kbd&gt;Enter&lt;/kbd&gt; change the autocompletion text to the currently selected item from the popup menu&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See &lt;a href="https://vimhelp.org/insert.txt.html#ins-completion"&gt;:h ins-completion&lt;/a&gt; for more details and other autocomplete features.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video demo&lt;/strong&gt;:&lt;/p&gt;
&lt;p align="center"&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;img alt="info" src="/images/info.svg" /&gt; See also my &lt;a href="https://github.com/learnbyexample/vim_reference"&gt;Vim Reference Guide&lt;/a&gt; and &lt;a href="https://learnbyexample.github.io/curated_resources/vim.html"&gt;curated list of resources for Vim&lt;/a&gt;.&lt;/p&gt;</description><author>learnbyexample</author><pubDate>Tue, 18 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://learnbyexample.github.io/tips/vim-tip-3/</guid></item><item><title>Beyond Faster JSON Support for iOS/macOS, Part 9: CSV and SQLite</title><link>https://blog.metaobject.com/2020/06/beyond-faster-json-support-for-iosmacos.html</link><description>When looking at the &lt;code&gt;MPWPlistStreaming&lt;/code&gt; protocol that I've been using for my
JSON parsing series, one thing that was probably noticeable is that it isn't particularly
JSON-focused.  In fact, it wasn't even initially designed for parsing, but for generating.&lt;p&gt;

So could we use this for other de-serialization tasks?  Glad you asked!&lt;p&gt;

&lt;h3&gt;CSV parsing&lt;/h3&gt;

One of the examples in my performance book involves parsing Comma Separated Values
quickly, within the context of getting the time to convert a 139Mb
 &lt;a href="https://en.wikipedia.org/wiki/General_Transit_Feed_Specification"&gt;GTFS&lt;/a&gt; file 
to something usable on the phone down from 20 minutes using 
using CoreData/SQLite to slightly less than a second using custom in-memory data structures
that are also several orders of magnitude faster to query on-device.&lt;p&gt;



The original project's CVS parser took around 18 seconds, which wasn't a significant
part of the 20 minutes, but when the rest only took a couple of hundred milliseconds,
it was time to make that part faster as well.  The result, slightly generalized,
is &lt;code&gt;MPWDelimitedTable&lt;/code&gt; ( &lt;a href="https://github.com/mpw/MPWFoundation/blob/master/Collections.subproj/MPWDelimitedTable.h"&gt;.h&lt;/a&gt; &lt;a href="https://github.com/mpw/MPWFoundation/blob/master/Collections.subproj/MPWDelimitedTable.m"&gt;.m&lt;/a&gt; ).&lt;p&gt;

The basic interface is block-based, with the block being called for every row in the 
table, called with a dictionary composed of the header row as keys and the contents
of the row as values.&lt;p&gt;


&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
-(void)do:(void(^)(NSDictionary* theDict, int anIndex))block;
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

Adapting this to the &lt;code&gt;MPWPlistStreaming&lt;/code&gt; protocol is straightforward:

&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
-(void)writeOnBuilder:(id )builder
{
    [builder beginArray];
    [self do:^(NSDictionary* theDict, int anIndex){
        [builder beginDictionary];
        for (NSString *key in self.headerKeys) {
            [builder writeObject:theDict[key] forKey:key];
        }
        [builder endDictionary];
    }];
    [builder endArray];
}
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

This is a quick-and-dirty implementation based on the existing API that is clearly
sub-optimal:  the API we call first constructs a dictionary from the row and the
header keys and then we iterate over it.  However, it works with our existing set 
of builders and doesn't build an in-memory representation of the entire CSV.&lt;p&gt;

It will also be relatively straightforward to invert this API usage, modifying the
low-level API to use &lt;code&gt;MPWPlistStreaming&lt;/code&gt; and then creating a higher-level
block- and dictionay-based API on top of that, in a way that will also work with
other &lt;code&gt;MPWPlistStreaming&lt;/code&gt;
clients.


&lt;h3&gt;SQLite&lt;/h3&gt;

Another tabular data format is SQL data bases.  On macOS/iOS, one very common database
is SQLite, usually accessed via CoreData or the excellent and much more light-weight
&lt;a href="https://github.com/ccgus/fmdb"&gt;fmdb&lt;/a&gt;.&lt;p&gt;

Having used fmdb myself before, and bing quite delighted with it, my first impulse was 
to write a &lt;code&gt;MPWPlistStreaming&lt;/code&gt; adapter for it, but after looking at the code
a bit more closely, it seemed  that it was doing quite a bit that I would not need for
&lt;code&gt;MPWPlistStreaming&lt;/code&gt;.&lt;p&gt;

I also think I saw the same trade-off between a convenient and slow convenience based
on &lt;code&gt;NSDictionary&lt;/code&gt; and a much more complex but potentially faster API
based on pulling individual type values.&lt;p&gt;

So Instead I decided to try and do something ultra simple that sits directly on
top of the SQLite C-API, and the implementation is really quite simple and
compact:&lt;p&gt;

&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
@interface MPWStreamQLite()

@property (nonatomic, strong) NSString *databasePath;

@end

@implementation MPWStreamQLite
{
    sqlite3 *db;
}

-(instancetype)initWithPath:(NSString*)newpath
{
    self=[super init];
    self.databasePath = newpath;
    return self;
}

-(int)exec:(NSString*)sql
{
    sqlite3_stmt *res;
    int rc = sqlite3_prepare_v2(db, [sql UTF8String], -1, &amp;amp;res, 0);
    @autoreleasepool {
        [self.builder beginArray];
        int step;
        int numCols=sqlite3_column_count(res);
        NSString* keys[numCols];
        for (int i=0;i &amp;lt; numCols; i++) {
            keys[i]=@(sqlite3_column_name(res, i));
        }
        while ( SQLITE_ROW == (step = sqlite3_step(res))) {
            @autoreleasepool {
                [self.builder beginDictionary];
                for (int i=0; i &amp;lt; numCols; i++) {
                    const char *text=(const char*)sqlite3_column_text(res, i);
                    if (text) {
                        [self.builder writeObject:@(text) forKey:keys[i]];
                    }
                }
                [self.builder endDictionary];
            }
        }
        sqlite3_finalize(res);
        [self.builder endArray];
    }
    return rc;
}

-(int)open
{
    return sqlite3_open([self.databasePath UTF8String], &amp;amp;db);
}

-(void)close
{
    if (db) {
        sqlite3_close(db);
        db=NULL;
    }
}

&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

Of course, this doesn't do a lot, chiefly it only reads, no updates, inserts or deletes.
However, the code is striking in its brevity and simplicity, while at the same time
being both convenient and fast, though with still some room for improvement.&lt;p&gt;

In my experience, you tend to not get all three of these properties at the same time:
code that is simple and convenient tends to be slow, code that is convenient and 
fast tends to be rather tricky and code that's simple and fast tends to be inconvenient
to use.&lt;p&gt;

How easy to use is it?  The following code turns a table into an array of dictionaries:



&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
#import &amp;lt;MPWFoundation/MPWFoundation.h&amp;gt;

int main(int argc, char* argv[]) {
   MPWStreamQLite *db=[[MPWStreamQLite alloc] initWithPath:@"chinook.db"];
   db.builder = [MPWPListBuilder new];
   if( [db open] == 0 ) {
       [db exec:@"select * from artists;"];
       NSLog(@"results: %@",[db.builder result]);
       [db close];
   } else {
       NSLog(@"Can't open database: %s\n", [db error]);
   }
   return(0);
}
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

This is pretty good, but probably roughly par for the course for returning a generic
data structure such as array of dictionaries, which is not going to be particularly
efficient.  (One of my first clues that CoreData's predecessor EOF wasn't particularly
fast was when I read that fetching raw dictionaries was an optimization, much faster than
fetching objects.)&lt;p&gt;


What if we want to get objects instead?  Easy, just replace the &lt;code&gt;MPWPListBuilder&lt;/code&gt;
with an &lt;code&gt;MPWObjectBuilder&lt;/code&gt;, parametrized with the class to create.  Well, and
define the class, but presumably you already havee that if the task is to convert to
objects of that class. And it cold obviously also be automated.&lt;p&gt;

&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;

#import &amp;lt;MPWFoundation/MPWFoundation.h&amp;gt;

@interface Artist : NSObject { }

@property (assign) long ArtistId;
@property (nonatomic,strong) NSString *Name;

@end

@implementation Artist

-(NSString*)description
{
	return [NSString stringWithFormat:@"&lt;%@:%p id: %ld name: %@&gt;",[self class],self,self.ArtistId,self.Name];
}

@end

int main(int argc, char* argv[]) {
   MPWStreamQLite *db=[[MPWStreamQLite alloc] initWithPath:@"chinook.db"];
   db.builder = [[MPWObjectBuilder alloc] initWithClass:[Artist class]];
   if( [db open] == 0) {
       [db exec:@"select * from artists"];
       NSLog(@"results: %@",[db.builder result]);
       [db close];
   } else {
       NSLog(@"Can't open database: %s\n", [db error]);
   }
   return(0);
}
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

Note that this does &lt;em&gt;not&lt;/em&gt; generate a plist representation as an intermediate
step, it goes straight from database result sets to objects.  The generic intermediate
"format" is the &lt;code&gt;MPWPlistStreaming&lt;/code&gt; protocol, which is a dematerialized 
representation, both plist and objects are peers.&lt;p&gt;


&lt;h3&gt;TOC&lt;/h3&gt;

&lt;a href="https://blog.metaobject.com/2020/04/somewhat-less-lethargic-json-support.html"&gt;Somewhat Less Lethargic JSON Support for iOS/macOS, Part 1: The Status Quo&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.metaobject.com/2020/04/somewhat-less-lethargic-json-support_12.html"&gt;Somewhat Less Lethargic JSON Support for iOS/macOS, Part 2: Analysis&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.metaobject.com/2020/04/somewhat-less-lethargic-json-support_14.html"&gt;Somewhat Less Lethargic JSON Support for iOS/macOS, Part 3: Dematerialization&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.metaobject.com/2020/04/equally-lethargic-json-support-for.html"&gt;Equally Lethargic JSON Support for iOS/macOS, Part 4: Our Keys are Small but Legion&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.metaobject.com/2020/04/less-lethargic-json-support-for.html"&gt;Less Lethargic JSON Support for iOS/macOS, Part 5: Cutting out the Middleman&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.metaobject.com/2020/04/somewhat-faster-json-support-for.html"&gt;Somewhat Faster JSON Support for iOS/macOS, Part 6: Cutting KVC out of the Loop&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.metaobject.com/2020/04/faster-json-support-for-iosmacos-part-7.html"&gt;Faster JSON Support for iOS/macOS, Part 7: Polishing the Parser&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.metaobject.com/2020/04/faster-json-support-for-iosmacos-part-8.html"&gt;Faster JSON Support for iOS/macOS, Part 8: Dematerialize All the Things!&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.metaobject.com/2020/06/beyond-faster-json-support-for-iosmacos.html"&gt;Beyond Faster JSON Support for iOS/macOS, Part 9: CSV and SQLite&lt;/a&gt;&lt;br /&gt;</description><author>metablog</author><pubDate>Sun, 16 Jan 2022 17:43:41 GMT</pubDate><guid isPermaLink="true">https://blog.metaobject.com/2020/06/beyond-faster-json-support-for-iosmacos.html</guid></item><item><title>Pseudonymous</title><link>https://www.marginalia.nu/log/43-pseodonymous/</link><description>&lt;p&gt;A person might think I&amp;rsquo;m illusive, writing and working under a pseudonym. It&amp;rsquo;s not that I&amp;rsquo;m hiding, if you send me an email, I&amp;rsquo;ll respond to you with an email address containing a decent chunk of my real name. It&amp;rsquo;s not out of shame I wear clothes.&lt;/p&gt;
&lt;p&gt;Besides bringing utility, marginalia.nu is an experiment, a bit of an art project, a place to challenge conventions and see what is and isn&amp;rsquo;t necessary.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Sat, 15 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/43-pseodonymous/</guid></item><item><title>Less-than-linear Fibonacci</title><link>https://specbranch.com/posts/fibonacci/</link><description>&lt;p&gt;Few interview problems are as notorious as the &amp;quot;Fibonacci&amp;quot; interview question. At first glance,
it seems good: Most people know something about the problem, and there are several
clever ways to achieve a linear time solution. Usually, in interviews, the linear time solution
is the expected solution. However, the Fibonacci problem is unique among interview problems in that
the expected solution is &lt;em&gt;not&lt;/em&gt; the optimal solution. There is an $O(1)$ solution, and to get there,
we need a little bit of linear algebra.&lt;/p&gt;</description><author>Speculative Branches</author><pubDate>Fri, 14 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://specbranch.com/posts/fibonacci/</guid></item><item><title>dsq: Commandline tool for running SQL queries against JSON, CSV, Excel, Parquet, and more.</title><link>http://notes.eatonphil.com/dsq.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-01-11-dsq.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Tue, 11 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/dsq.html</guid></item><item><title>Analyzing large JSON files via partial JSON parsing</title><link>http://notes.eatonphil.com/analyzing-large-json-files-via-partial-json-parsing.html</link><description>&lt;p&gt;This is an external post of mine. Click
&lt;a href="https://datastation.multiprocess.io/blog/2022-01-06-analyzing-large-json-files-via-partial-json-parsing.html"&gt;here&lt;/a&gt;
if you are not redirected.&lt;/p&gt;</description><author>Notes on software development</author><pubDate>Thu, 06 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/analyzing-large-json-files-via-partial-json-parsing.html</guid></item><item><title>Probabilistic spin glass - Part V</title><link>https://bytepawn.com/probabilistic-spin-glass-part-v.html</link><description>&lt;p&gt;I use Monte Carlo simulations to explore the dynamic behaviour of probabilistic spin glasses, specifically how saturation scales with $p$ and $N$. &lt;br /&gt;&lt;br /&gt;&lt;img alt="." src="/images/spin_glass_p5_3.png" style="width: 300px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Thu, 06 Jan 2022 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/probabilistic-spin-glass-part-v.html</guid></item><item><title>The year in books: 11 to recommend in 2021</title><link>http://notes.eatonphil.com/year-in-books-2021.html</link><description>&lt;p&gt;Last year (2021) I finished 17 books, a five year low. But that's ok!
4 fiction and 13 non-fiction. Another 30 started but not finished.&lt;/p&gt;
&lt;h3 id="non-fiction"&gt;Non-fiction&lt;/h3&gt;&lt;p&gt;It seems I was pretty focused on business history books and history of
tech. The 8 non-fiction books I liked the most:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/34626431-designing-data-intensive-applications"&gt;Designing Data-Intensive Applications&lt;/a&gt;, a must-read for anyone interacting with a database&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/24715220-my-years-with-general-motors"&gt;My Years with General Motors&lt;/a&gt;, the business school classic; truly a good read. But sad to know that shortly after written, GM succumbs to the Japanese and South Korean competition&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/49195924-no-rules-rules"&gt;No Rules Rules: Netflix and the Culture of Reinvention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/55297149-working-backwards"&gt;Working Backwards: Insights, Stories, and Secrets from Inside Amazon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/54216469-working-in-public"&gt;Working in Public: The Making and Maintenance of Open Source Software&lt;/a&gt;, my review &lt;a href="https://www.goodreads.com/review/show/3478346828?book_show_action=false&amp;amp;from_review_page=1"&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/22401445-intel-trinity-the"&gt;The Intel Trinity&lt;/a&gt;, an early history of Intel&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/19383579-the-hp-way"&gt;The HP Way&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/58208477-play-nice-but-win"&gt;Play Nice But Win&lt;/a&gt;, the story of Dell computers&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/36316219-west-with-the-night"&gt;West with the Night&lt;/a&gt;, beautiful memoir recommended by Ernest Hemingway and written in a similar style. Much more enjoyable than the other more popular colonial-African memoir, Out of Africa.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="the-rest"&gt;The rest&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/16059922-pour-your-heart-into-it"&gt;Pour Your Heart Into It: How Starbucks Built a Company One Cup at a Time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/43063719-jump-starting-america"&gt;Jump-Starting America: How Breakthrough Science Can Revive Economic Growth and the American Dream&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/9118033-rework"&gt;ReWork&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/297901.Russia_and_the_Russians"&gt;Russia and the Russians: A History&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fiction"&gt;Fiction&lt;/h3&gt;&lt;p&gt;The 3 fiction books I liked the most:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/12970829-a-very-british-coup"&gt;A Very British Coup&lt;/a&gt;, hilarious and depressing. A great companion to the TV show "Yes, Minister"&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/8862633-mort"&gt;Mort&lt;/a&gt;, Terry Pratchett is a very funny author&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18625885-selected-stories-of-philip-k-dick"&gt;Selected Stories of Philip K Dick&lt;/a&gt;, depressing and dystopian but very well written. I would not read again because it's too depressing&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="the-rest"&gt;The rest&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/51135871-there-and-never-ever-back-again"&gt;There and NEVER, EVER BACK AGAIN: A Dark Lord's Diary&lt;/a&gt;, I was looking for more parodies like Bored of the Rings (which itself wasn't great). This was worse&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2022"&gt;2022&lt;/h3&gt;&lt;p&gt;This year I'm interested in continuing to find good business books and
good books on the history of tech. I'm also getting into more American
history to make up for all the years of not paying attention in high
school.&lt;/p&gt;
&lt;p&gt;I'm continuing to try to find good memoirs and fiction by non-English
authors.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Starting the blog-year off gently with my recap of 2021 in books.&lt;br /&gt;&lt;br /&gt;I spent too much time watching TV and trying new video games to keep up with past years 😅&lt;a href="https://t.co/5mfXbBnihk"&gt;https://t.co/5mfXbBnihk&lt;/a&gt; &lt;a href="https://t.co/ZHmPsUcr3g"&gt;pic.twitter.com/ZHmPsUcr3g&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1478764597033283591?ref_src=twsrc%5Etfw"&gt;January 5, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Wed, 05 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/year-in-books-2021.html</guid></item><item><title>Dark</title><link>https://www.marginalia.nu/log/42-dark/</link><description>&lt;p&gt;As is often the case these dark winter seasons, I&amp;rsquo;ve fallen into a bit of a funk. Inspiration it seems is as rare as sunlight, and sunlight is scarce indeed in the winters of the north.&lt;/p&gt;
&lt;p&gt;I do know what is missing, novelty. I&amp;rsquo;ve fallen into consuming &amp;ldquo;content&amp;rdquo;. Infinite scroll is the torture rack of the spirit. What is necessary doing new things and seeing new inspiring sights, exposing myself to new inspiring thoughts.&lt;/p&gt;</description><author>Weblog on marginalia.nu</author><pubDate>Sun, 02 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.marginalia.nu/log/42-dark/</guid></item><item><title>Looking ahead to 2022</title><link>https://benovermyer.com/blog/2022/01/looking-ahead-to-2022/</link><description>&lt;p&gt;2022 promises to be a year of big changes. We're moving to North Carolina sometime in the first quarter. I'm planning on leaning hard into biking and beach culture, which should have the side effect of helping me become fit again. I want to try surfing and snorkeling and other such things.&lt;/p&gt;
&lt;p&gt;For Iron Arachne, I plan to work on enhancing existing generators over adding more. In particular, I want to make them more customizable and allow better export options. The culture, heraldry, and region generators will see the bulk of the changes here. I will probably try again to write a map generator to go with the region generator. Though I have yet to understand the math behind it, I keep trying. Eventually I'll get it.&lt;/p&gt;
&lt;p&gt;For fitness, my strategy is fairly simple. I'll spend less of my free time in front of a computer screen and more on running around outside. I hope to make a habit of logging off after work and going for a run or something. On weekends I'll need a different pivot point; maybe before breakfast I'll go out. That I'm less sure on. My doctor continues to recommend cholesterol medication, so I might finally take that advice.&lt;/p&gt;
&lt;p&gt;I want to rejoin the Society for Creative Anachronism in 2022. I'll be in a brand new area completely devoid of past drama. It'll be a good opportunity to reconnect with more physical hobbies I used to have. I already have a device in review at the society level; hopefully it's accepted, because it's perfect for a cook who likes the beach.&lt;/p&gt;
&lt;p&gt;Final Fantasy XIV continues to hold my interest, which is rare for an MMO. My free company, the Mystic Exiles, is a great group of people. There are a couple individuals in particular that I have fun playing with. Maybe someday I'll get to meet them all in person. I got the FF14 cookbook for Christmas, and I plan on making several dishes out of it this year. Maybe I'll write about my experiences with it here. Maybe I'll write more about what I do in FF14 in general, actually. That could be fun.&lt;/p&gt;
&lt;p&gt;For my 40th birthday this year we're going to Hawai'i. I'm really looking forward to that trip. It's only a couple months away now. It gives me another incentive to rock the fitness thing early and hard. It's also possible that we'll be going to Italy with my family this year. Sarah and I are learning Italian, though she's much better about the learning habit than I am. I need to devote more time to it.&lt;/p&gt;
&lt;p&gt;Assuming we're able to rent a house with no shared walls or at least thick walls, I also want to get back into playing musical instruments. I have a dizi flute that I've only just started to learn how to play. If the stars align, maybe I'll get a piano and start playing that again too. For now though, I'm only committing to learning the dizi.&lt;/p&gt;
&lt;p&gt;All of the above makes for a pretty action-packed 2022. Hopefully nothing crazy happens that throws all of this out the window. If it does, well, my main goal will still be improving fitness and health.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Sat, 01 Jan 2022 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2022/01/looking-ahead-to-2022/</guid></item></channel></rss>