<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Boots</title>
    <description>The latest articles on DEV Community by Boots (@brettimus).</description>
    <link>https://dev.to/brettimus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F152823%2F0aa2b75f-55a6-40d3-9fdf-e37bd10d16f7.jpeg</url>
      <title>DEV Community: Boots</title>
      <link>https://dev.to/brettimus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brettimus"/>
    <language>en</language>
    <item>
      <title>Retrieval Augmented Geese - Semantic Search with the HONC Stack</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Wed, 13 Nov 2024 18:13:21 +0000</pubDate>
      <link>https://dev.to/fiberplane/retrieval-augmented-geese-semantic-search-with-the-honc-1e5h</link>
      <guid>https://dev.to/fiberplane/retrieval-augmented-geese-semantic-search-with-the-honc-1e5h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🪿 &lt;em&gt;&lt;strong&gt;Register for November's &lt;a href="https://honc.dev/honcathon" rel="noopener noreferrer"&gt;HONCathon here&lt;/a&gt;&lt;/strong&gt; - ship apps, win prizes - sponsored by Cloudflare, Drizzle, Fiberplane, and Neon&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;If you've heard the term RAG or "Retrieval Augmented Generation" lately, you may have asked yourself something like "What is that?" or "How did such a ridiculous acronym get so popular?"&lt;/p&gt;

&lt;p&gt;I can't answer to the way it was named, but I can tell you this: One of the core pieces of RAG systems is semantic search, which helps map the underlying meaning (&lt;em&gt;semantics&lt;/em&gt;) of a search query to the closest-related meaning of a set of documents in a database.&lt;/p&gt;

&lt;p&gt;In this post, we'll go over how to implement basic semantic search with &lt;a href="https://honc.dev/" rel="noopener noreferrer"&gt;the HONC stack&lt;/a&gt;, using Hono as an api framework, Neon Postgres as a database, Drizzle as a typesafe ORM, and Cloudflare Workers as the serverless deployment platform.&lt;/p&gt;

&lt;p&gt;We'll build a small semantic search engine for Cloudflare's documentation, giving us a system that understands the meaning behind search queries, not just keyword matches.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;a href="https://github.com/fiberplane/create-honc-app/tree/main/examples/cf-retrieval-augmented-goose" rel="noopener noreferrer"&gt;Follow along with the code on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A Conceptual Primer
&lt;/h2&gt;

&lt;p&gt;Before we get started, let's go over some basic concepts. This will be especially helpful if you're not already familiar with vectors and embeddings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Already familiar with embeddings?&lt;/strong&gt;&lt;br&gt;
Feel free to skip past this section if you already know about vectors and embeddings and all that jazz.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Vectors
&lt;/h3&gt;

&lt;p&gt;For our purposes, vectors are lists of numbers, like &lt;code&gt;[1, 2, 3, 4, 5]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vectors are described in terms of their length. An example of a vector of length two would be &lt;code&gt;[.68, .79]&lt;/code&gt; and a vector of length three would look like &lt;code&gt;[.883, .24, .6001]&lt;/code&gt;. Simple!&lt;/p&gt;

&lt;p&gt;When vectors are all the same length, you can compare and manipulate them in interesting ways, by adding them together, subtracting them, or finding the distance between them.&lt;/p&gt;

&lt;p&gt;All of this will be relevant in a bit, I promise 🙂&lt;/p&gt;

&lt;h3&gt;
  
  
  Embeddings
&lt;/h3&gt;

&lt;p&gt;Put shortly, embeddings are vector representations of the meanings of words and phrases… But. Well. That's a little abstract.&lt;/p&gt;

&lt;p&gt;My favorite analogy for why these are useful and how they work comes from from AI researcher &lt;a href="https://thesephist.com/" rel="noopener noreferrer"&gt;Linus Lee.&lt;/a&gt; He draws a comparison to colors. There's a difference between describing a color with a name, like &lt;code&gt;"blue"&lt;/code&gt;, versus with an RGB value &lt;code&gt;rgb(0, 0, 255)&lt;/code&gt;. In this case, the RGB value is a vector of length three, &lt;code&gt;(0, 0, 255)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we wanted to mix some red into the named color &lt;code&gt;"blue"&lt;/code&gt; and make a new color that's just a &lt;em&gt;little&lt;/em&gt; more purple, how would we do that?&lt;/p&gt;

&lt;p&gt;Well, if all we have is the name of the color, there's not much we can do. We'd just invent a new color and give it a new name, like &lt;code&gt;"purpleish blue"&lt;/code&gt;. With an RGB value, though, we can simply "add" some red:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rgb(20, 0 , 0) + rgb(0, 0, 255) = rgb(20, 0, 255)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Because we chose to represent our color with &lt;em&gt;vectors of numbers&lt;/em&gt;, we can do math on it. We can change it around, mix it with other colors, and have an all around good time with it.&lt;/p&gt;

&lt;p&gt;Embeddings are a way for us to do this kind of math on human language. Embeddings are vectors, like RGB values, except they're much larger.&lt;/p&gt;

&lt;p&gt;How would you "do math on human language" though? Borrowing an example from the trusty Internet, let's say we have a vector for the word &lt;code&gt;"king"&lt;/code&gt;, and a vector for the words &lt;code&gt;"man"&lt;/code&gt; and &lt;code&gt;"woman"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we subtract the vector for &lt;code&gt;"man"&lt;/code&gt; from the vector for &lt;code&gt;"king"&lt;/code&gt; , then add the vector for the word &lt;code&gt;"woman"&lt;/code&gt;. What would you expect we get?&lt;br&gt;
Wild enough, we would get a vector &lt;em&gt;very very close&lt;/em&gt; to the one for the word &lt;code&gt;"queen"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Pretty neat, huh?&lt;/p&gt;
&lt;h3&gt;
  
  
  Vector Search
&lt;/h3&gt;

&lt;p&gt;Searching across vectors usually refers to looking for vectors that are similar to one another.&lt;/p&gt;

&lt;p&gt;In this case, we think of similarity in terms of distance. Two vectors that are close to one another are similar. Two vectors that are far apart are different.&lt;/p&gt;

&lt;p&gt;So, in a database that stores vectors, we can calculate the distance between an input vector, and all vectors in the database, and return only the ones that are most similar.&lt;br&gt;
In this post, you will see a reference to "cosine similarity", which is a way to calculate the distance between two vectors. So, don't get freaked if we start talking about cosines.&lt;/p&gt;

&lt;p&gt;Basically, instead of looking for exact matches or keyword matches for a user's query, we look for "semantically similar matches" based off of cosine distance.&lt;/p&gt;
&lt;h2&gt;
  
  
  How Do We Start?
&lt;/h2&gt;

&lt;p&gt;To perform semantic search, we need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a database that supports vector embeddings&lt;/li&gt;
&lt;li&gt;a way to vectorize text&lt;/li&gt;
&lt;li&gt;a way to search for similar vectors in the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be entirely frank, the hardest part of building semantic search is knowing how to parse and split up your target documents text into meaningful chunks.&lt;/p&gt;

&lt;p&gt;I spent most of my time on this project just pulling down, compiling, and chunking the Cloudflare documentation. After that, the search part was easy-peasy.&lt;br&gt;
I will gloss over the tedious parts of this below, but I've provided a link to the script that processes the documentation, for anyone who is interested.&lt;/p&gt;

&lt;p&gt;That said, let's go over the stack and database models we'll be using for the actual searching part.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Stack
&lt;/h3&gt;

&lt;p&gt;We want to expose a simple API for users to search the Cloudflare documentation. Then we want some tools for storing the documents and their embeddings, as well as querying them.&lt;/p&gt;

&lt;p&gt;Here's the stack we'll be using for all of this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hono&lt;/strong&gt;: A lightweight web framework for building typesafe APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neon Postgres&lt;/strong&gt;: Serverless postgres database for storing documents and vector embeddings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI&lt;/strong&gt;: To vectorize documentation content and user queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drizzle ORM&lt;/strong&gt;: For constructing type-safe database operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare Workers&lt;/strong&gt;: To host the API on a serverless compute platform&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Setting up the Database
&lt;/h3&gt;

&lt;p&gt;First, we define a schema using Drizzle ORM.&lt;/p&gt;

&lt;p&gt;When we craft our database models, we have to think of what kind of search results we want to return.&lt;br&gt;
This leads us to the idea of "chunking", which is the process of splitting up the text into smaller chunks.&lt;/p&gt;

&lt;p&gt;The logic is: We don't want to match a user's query to entire documents, because that would return a lot of irrelevant results.&lt;br&gt;
Instead, we should split up each documentation page into smaller chunks, and match the user's query to the most semantically similar chunks.&lt;/p&gt;

&lt;p&gt;Since we're working witha relational database, we can define a schema for the documents and chunks, where each document can have many chunks.&lt;/p&gt;

&lt;p&gt;So, our Drizzle schema defines two main tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;documents&lt;/code&gt;: Stores the original documentation pages&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chunks&lt;/code&gt;: Stores content chunks with their vector embeddings
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pgTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;documents&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;defaultRandom&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pgTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chunks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;defaultRandom&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;document_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;documents&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;chunkNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chunk_number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;embedding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;dimensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1536&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;jsonb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;metadata&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;$type&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once we define a schema, we can create the tables in our database.&lt;br&gt;
If you're following along on GitHub, you can run the commands below to create the tables.&lt;br&gt;
Under the hood, we use Drizzle to generate migration files and apply them to the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm db:generate
pnpm db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, with our database set up, we can move on to processing the documentation itself into vector embeddings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Processing Documentation
&lt;/h3&gt;

&lt;p&gt;The heart of our system is the document processing pipeline. It's a bit of a beast.&lt;br&gt;
I'm going to move through this quickly, but you can see the full implementation in&lt;br&gt;
&lt;a href="https://github.com/fiberplane/create-honc-app/blob/main/examples/cf-retrieval-augmented-goose/scripts/create-vectors.ts" rel="noopener noreferrer"&gt;&lt;code&gt;./src/scripts/create-vectors.ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Takes HTML documentation files as input&lt;/li&gt;
&lt;li&gt;Uses GPT-4o to clean and chunk the content&lt;/li&gt;
&lt;li&gt;Generates embeddings for each chunk&lt;/li&gt;
&lt;li&gt;Stores everything in our Neon Postgres database&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once this runs, we have a database full of document chunks and their embeddings, and we can move on to building the search API.&lt;br&gt;
Probably the most interesting part of this script is how we use GPT-4o to clean and chunk the content. In some cases, this might be&lt;br&gt;
cost prohibitive, but for our use case, it was a no-brainer. We only need to run this once, and it was a lot smarter than any heuristics I would've defined myself.&lt;/p&gt;

&lt;p&gt;If you're following along on GitHub, I commend you. You can run these commands to process the documentation. (Please file an issue if you run into any problems.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Process the Cloudflare documentation&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;data
bash copy-cf-docs.sh
&lt;span class="nb"&gt;cd&lt;/span&gt; ../
&lt;span class="c"&gt;# Create the vector embeddings&lt;/span&gt;
pnpm run vectors:create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Search API
&lt;/h2&gt;

&lt;p&gt;When a user makes a search request, we do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Convert their query into a vector embedding&lt;/li&gt;
&lt;li&gt;Use cosine similarity to find the most relevant chunks for their query&lt;/li&gt;
&lt;li&gt;Return the top matches back to the user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why convert their query into a vector embedding? We want to find the most semantically similar chunks,&lt;br&gt;
so we need to represent their query in the same format as our database chunks.&lt;/p&gt;

&lt;p&gt;The search endpoint is surprisingly simple thanks to Hono.&lt;br&gt;
We define a &lt;code&gt;GET&lt;/code&gt; route that takes &lt;code&gt;query&lt;/code&gt; and &lt;code&gt;similarity&lt;/code&gt; parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Parse query parameters&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;similarityCutoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseFloat&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;similarity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we make a request to OpenAI to create an embedding for the user's search query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Initialize the OpenAI client&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Create embedding for the search query&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;embeddingResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-embedding-3-small&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userQueryEmbedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;embeddingResult&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we craft a similarity search based on the cosine distance between the query embedding and each chunk's embedding.&lt;br&gt;
Here, the &lt;code&gt;drizzleSql&lt;/code&gt; helper is the &lt;code&gt;sql&lt;/code&gt; helper exported by Drizzle, which has been renamed for clarity.&lt;br&gt;
It allows us to construct type-safe sql expressions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Craft a similarity search query based on the cosine distance between&lt;/span&gt;
  &lt;span class="c1"&gt;// the embedding of the user's query, and the embedding of each chunk from the docs.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;similarityQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;drizzleSql&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`1 - (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;cosineDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;queryEmbedding&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Search for chunks with similarity above the cutoff score&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chunks&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="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;similarity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;similarityQuery&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;drizzleSql&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;similarityQuery&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;similarityCutoff&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;drizzleSql&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;similarityQuery&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; desc`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That leaves us with a list of chunks that are semantically similar to the user's query!&lt;br&gt;
We can choose to render these results however we see fit.&lt;/p&gt;

&lt;p&gt;When we use Fiberplane to test the search API, we can see the timeline of the request, including the embedding generation, similarity search, and result rendering.&lt;br&gt;
We can also see the raw SQL that was executed, which is a little unwieldy since we're dealing with vectorized queries:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq5kjih2jga0x20cm9vo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq5kjih2jga0x20cm9vo.png" alt="timeline of search request" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it! We've built a semantic search engine with the HONC stack.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Magic of Vector Search
&lt;/h2&gt;

&lt;p&gt;What makes this more powerful than regular text search? Again, vector embeddings capture semantic meaning. For example, a search for "how to handle errors in Workers" will find relevant results even if they don't contain those exact words.&lt;/p&gt;

&lt;p&gt;Neon makes this simple, easy, and scalable by allowing efficient similarity searches over high-dimensional vectors &lt;em&gt;out of the box&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However, that doesn't mean that vector search is &lt;em&gt;the only&lt;/em&gt; tool for retrieval. Any robust system should consider the trade-offs of vector search vs. keyword search, and likely combine the two.&lt;/p&gt;
&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;a href="https://cf-retrieval-augmented-goose.mies.workers.dev/" rel="noopener noreferrer"&gt;See it in action - Live Demo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Deploying to Cloudflare Workers is straightforward. We just push the code and set the secrets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set your secrets&lt;/span&gt;
wrangler secret put DATABASE_URL
wrangler secret put OPENAI_API_KEY

&lt;span class="c"&gt;# Deploy&lt;/span&gt;
pnpm run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you're looking for a quick way to get up and running with semantic search, this should give you a solid starting point.&lt;/p&gt;

&lt;p&gt;Worth noting: there are a lot of libraries out there that can take care of the heavy lifting of building RAG systems.&lt;br&gt;
At Fiberplane, we've built smaller systems with &lt;a href="https://www.llamaindex.ai/" rel="noopener noreferrer"&gt;Llamaindex&lt;/a&gt; and &lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;Langchain&lt;/a&gt;,&lt;br&gt;
but for simpler use cases, I found myself wading through documentation and GitHub issues more than I'd like.&lt;br&gt;
A higher-level library can be very helpful for bigger applications, but for something this simple, I think the core concepts are valuable to implement and understand.&lt;/p&gt;

&lt;p&gt;To that end, the full code for everything in this post is available on GitHub, and you can adapt it for your own needs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;a href="https://github.com/fiberplane/create-honc-app/tree/main/examples/cf-retrieval-augmented-goose" rel="noopener noreferrer"&gt;Get the code on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Otherwise, don't forget to check out the &lt;a href="https://honc.dev/" rel="noopener noreferrer"&gt;HONC stack&lt;/a&gt; for more examples of building with Hono, Drizzle, Neon, and Cloudflare. &lt;/p&gt;

</description>
      <category>honc</category>
      <category>rag</category>
      <category>semanticsearch</category>
      <category>cloudflare</category>
    </item>
    <item>
      <title>A Quick JS Reduction: My possibly-too-clever way to reduce an array into one object in javascript</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Mon, 20 Apr 2020 11:48:32 +0000</pubDate>
      <link>https://dev.to/brettimus/a-quick-js-reduction-my-possibly-too-clever-way-to-reduce-an-array-into-one-object-in-javascript-2jf6</link>
      <guid>https://dev.to/brettimus/a-quick-js-reduction-my-possibly-too-clever-way-to-reduce-an-array-into-one-object-in-javascript-2jf6</guid>
      <description>&lt;p&gt;Let's say you have an array of &lt;code&gt;user&lt;/code&gt; objects, all with unique IDs, but you want to group them in a single object by their &lt;code&gt;id&lt;/code&gt;s.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// These are your only users&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Paul&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ringo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;George&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An easy way to do this using &lt;code&gt;Array.prototype.reduce&lt;/code&gt; without creating too many intermediary objects would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersGroupedById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;u&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="nx"&gt;u&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="p"&gt;{})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have a feeling every linter in the world would cry linty tears upon seeing this. But honestly, I kind of like it! &lt;/p&gt;

&lt;p&gt;Does this code offend you? How would you do this?&lt;/p&gt;

&lt;p&gt;My alternatives were:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Create objects willy-nilly because they are cheap&lt;/span&gt;
&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;u&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="nx"&gt;u&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="c1"&gt;// Use Object.assign to avoid spread syntax, still create a new object for every iteration&lt;/span&gt;
&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&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="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;u&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="nx"&gt;u&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="c1"&gt;// Arguably more readable version of the featured solution&lt;/span&gt;
&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;u&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="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>discuss</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Twenty-second article! An important difference between parseInt and + in javascript</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Tue, 14 Apr 2020 07:48:43 +0000</pubDate>
      <link>https://dev.to/brettimus/twenty-second-article-an-important-difference-between-parseint-and-in-javascript-47pi</link>
      <guid>https://dev.to/brettimus/twenty-second-article-an-important-difference-between-parseint-and-in-javascript-47pi</guid>
      <description>&lt;p&gt;I'll be brief! &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;parseInt('.3', 10)&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;returns &lt;code&gt;NaN&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;+'.3'&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;returns &lt;code&gt;0.3&lt;/code&gt; (a &lt;code&gt;Number&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;+&lt;/code&gt; operator might be slower than &lt;code&gt;parseInt&lt;/code&gt;, but it's a bit more intuitive imo... &lt;em&gt;and my goodness the title was almost as long as the article itself&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>javascript</category>
    </item>
    <item>
      <title>If you could only get one tech newsletter, what would it be?</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Fri, 10 Apr 2020 08:35:09 +0000</pubDate>
      <link>https://dev.to/brettimus/if-you-could-only-get-one-tech-newsletter-what-would-it-be-5dj9</link>
      <guid>https://dev.to/brettimus/if-you-could-only-get-one-tech-newsletter-what-would-it-be-5dj9</guid>
      <description>&lt;p&gt;&lt;strong&gt;What's one newsletter or digest that you could not live without as a developer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I realized I get close to ten weekly newsletters about tech-related things.&lt;/p&gt;

&lt;p&gt;I certainly do not read them all every week. I try to glance through a few (especially when the subject line is interesting) when I'm waiting for builds and what have you, but yeah. I'm thinking of unsubscribing from a handful to reduce inbox clutter, which got me to thinking: Which one gives me the most consistent value?&lt;/p&gt;

&lt;p&gt;As of this moment, I'd personally say &lt;a href="https://zerotomastery.io/blog/?tag=WDM" rel="noopener noreferrer"&gt;Web Dev Monthly&lt;/a&gt; by Andrei Neagoie. He does an end-of-the-month summary of the most important web development happenings for that month. I know "most important" depends greatly from person to person, but in my opinion his round-ups are pretty spot on.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>productivity</category>
      <category>newsletters</category>
    </item>
    <item>
      <title>Does dev.to ever just hang and not load for you?</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Sat, 04 Apr 2020 08:54:30 +0000</pubDate>
      <link>https://dev.to/brettimus/does-dev-to-ever-just-hang-and-not-load-for-you-1k41</link>
      <guid>https://dev.to/brettimus/does-dev-to-ever-just-hang-and-not-load-for-you-1k41</guid>
      <description>&lt;p&gt;Hey! So. It never occurred to me to check if others were experiencing this bug... on &lt;code&gt;dev&lt;/code&gt; itself!&lt;/p&gt;

&lt;p&gt;Simple question though: Do you ever enter the URL, and nothing happens? Like the browser progress thingy in the address bar makes some moves, but then it just freezes?&lt;/p&gt;

&lt;p&gt;If so, you might be entitled to compensation!&lt;/p&gt;

&lt;p&gt;No. Not really. But! You might be hitting a ServiceWorker bug that I just submitted a PR for!&lt;/p&gt;

&lt;p&gt;If you're experiencing this bug as well, could you comment on &lt;a href="https://github.com/thepracticaldev/dev.to/issues/5434"&gt;this issue on GitHub&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;It'd be nice for me to know the impact of what I'm trying to fix!&lt;/p&gt;

&lt;p&gt;Thanks,&lt;/p&gt;

&lt;p&gt;B&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>dev</category>
      <category>serviceworkers</category>
      <category>bug</category>
    </item>
    <item>
      <title>Three data structures you do not need to know in 2020</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Fri, 03 Apr 2020 22:34:50 +0000</pubDate>
      <link>https://dev.to/brettimus/three-useless-data-structures-you-do-not-need-to-know-in-2020-mdo</link>
      <guid>https://dev.to/brettimus/three-useless-data-structures-you-do-not-need-to-know-in-2020-mdo</guid>
      <description>&lt;p&gt;It seems that you, dear reader, have been compelled to brush up on your data structures, or at least the ones that you will never, ever need to know. Ever. &lt;/p&gt;

&lt;p&gt;I commend your studiousness. As a reward, here are three useless data structures that you'll never need to know about, neither now nor for the remainder of the current garbage year that we're calling ✨&lt;em&gt;&lt;strong&gt;2020&lt;/strong&gt;&lt;/em&gt;✨.&lt;/p&gt;

&lt;h1&gt;
  
  
  🌳 1. The giving trie
&lt;/h1&gt;

&lt;p&gt;The giving trie is a variant of the classic German-speaking &lt;em&gt;&lt;strong&gt;trie&lt;/strong&gt;&lt;/em&gt;, except this data structure is only half German. (Don't worry, the other half is actually quite friendly&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.)&lt;/p&gt;

&lt;p&gt;The giving trie has no interface to insert new items. It can only remove its elements until there’s nothing left but a nebulous melancholic log message that confuses young children and adults alike.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;GivingTrie&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;OLD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I am now an old trie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;initialTrieStuff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_trieStuff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialTrieStuff&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;everything&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_trieStuff&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_trieStuff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;everything&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I only get old. That is all I do. I am a Trie.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;takeMore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remainingTrieThings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_trieStuff&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remainingTrieThings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_trieStuff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;console&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;All I have left is this log message.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;But I am happy.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;But there is nothing left of me.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Also I am a trie.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/*********************
 *** Example Usage *** 
 *********************/&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;GivingTrie&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GivingTrie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;takeMore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// Prints:&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; All I have left is this log message.&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; But I am happy.&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; But there is nothing left of me.&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; Also I am a trie.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝  Also worth noting is that the giving trie is, in fact, nothing like a trie at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  🐒 2. The linked-by-a-barrel-of-monkeys list
&lt;/h1&gt;

&lt;p&gt;Typically, linked lists have banal, straight pointers between their nodes. &lt;/p&gt;

&lt;p&gt;The linked-by-a-barrel-of-monkeys list, on the other hand, is a linked list where each node is connected by tiny monkeys that link arms with each other. Hence, its name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/JcEbzHIM7lJBe/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/JcEbzHIM7lJBe/giphy.gif" alt="omfg two baby chimps embracing each other"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The thing about these tiny monkeys is that they are constantly moving around, changing places, etc, which makes the &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;prev&lt;/code&gt; methods much more whimsical than a traditional linked list. &lt;/p&gt;

&lt;p&gt;Usage of &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;prev&lt;/code&gt; is subject to random monkey-business. Their values change on each access, and a node could possibly link back to itself or start flying through Oz. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Proper use of the &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;prev&lt;/code&gt; accessors should guard against potential &lt;code&gt;FlyingToOzError&lt;/code&gt;s, since these are thrown  roughly 10% of the time you access said properties. (The monkeys really like Oz.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One last note: This data structure always has a &lt;code&gt;tail&lt;/code&gt; property, which, when accessed, returns a gif of a surprised or angered monkey.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;FlyingToOzError&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FlyingToOzError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;class&lt;/span&gt; &lt;span class="nx"&gt;LinkedBarrelOfMonkeysList&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Utility getter that might throw a FlyingToOzError&lt;/span&gt;
  &lt;span class="nx"&gt;pickRandomOrFlyToOz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldFlyToOz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shouldFlyToOz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FlyingToOzError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OOaAOo I FLY TO OZ!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;initialValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bomInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialValues&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="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pickRandomOrFlyToOz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bomInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pickRandomOrFlyToOz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bomInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;writable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OOoOOAAaAA NO POL TAIL!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://media.giphy.com/media/l378hyTQvH3bCdD2g/giphy.gif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="cm"&gt;/*********************
 *** Example Usage *** 
 *********************/&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bomList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;LinkedBarrelOfMonkeysList&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;bomList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tail&lt;/span&gt; 
&lt;span class="c1"&gt;// This will print a warning, along with a link to the gif below&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/l378hyTQvH3bCdD2g/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/l378hyTQvH3bCdD2g/giphy.gif" alt="Confused monkey"&gt;&lt;/a&gt;&lt;/p&gt;
OOoOOAAaAA NO POL TAIL



&lt;p&gt;Say what you will about these nondeterministic rascals—they’re a heck of a lot more fun than your traditional linked lists.&lt;/p&gt;

&lt;h1&gt;
  
  
  🤤 3. The lack of priorities queue
&lt;/h1&gt;

&lt;p&gt;The lack of priorities queue uses a first-Doritos-last-whatever algorithm to resolve which element it should return next. &lt;/p&gt;

&lt;p&gt;The function for accessing the next item in the queue is asynchronous, and does not have a timeout mechanism. You just have to chill and be patient. &lt;/p&gt;

&lt;p&gt;A common workaround to this queue’s inconsistent priority ranking is to wrap known high priority items inside a struct-like &lt;code&gt;Tortilla&lt;/code&gt;, as if it were a virtual burrito. &lt;code&gt;Tortilla&lt;/code&gt;s provide a priority boost to their wrapped values&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Note that a &lt;code&gt;nap&lt;/code&gt; subroutine may be implemented to reduce lag, but it’s not guaranteed to work.&lt;/p&gt;

&lt;p&gt;For this data structure, I provide no reference implementation. I might write one like next week or something or whatever.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤦🏻‍♂️ Conclusion
&lt;/h2&gt;

&lt;p&gt;There you have it. Three useless data structures that you will never use. I hope you learned something useless.&lt;/p&gt;

&lt;p&gt;Frankly, I'm kind of surprised you made it this far. This is complicated stuff. Really complicated! Why not reward yourself with a little nap?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/d5mI2F3MxCTJu/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/d5mI2F3MxCTJu/giphy.gif" alt="sloth takin' a nap"&gt;&lt;/a&gt;&lt;/p&gt;
this guy knos what i'm talkin bout



&lt;p&gt;💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;/p&gt;

&lt;p&gt;💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;/p&gt;

&lt;p&gt;💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;br&gt;
💤&lt;/p&gt;

&lt;p&gt;&lt;em&gt;...Hey! If you're still awake why not hit the follow button? You'll get a notification when I implement that &lt;code&gt;LackOfPrioritiesQueue&lt;/code&gt;!&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;em&gt;Also Entschuldigung. Ich muss es hier sagen dass die Deutsche Sprache, Kultur, und Menschen gefallen mir sehr. (Ich träge manchmal Lederhosen. Ernsthaft!) Ich wollte am Anfang nur einen kleinen Witz machen. Hoffentlich ist der nicht ganz in die Hose gegangen&lt;/em&gt; 😅 🇩🇪 🥨 🍻 ❤️ ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;In some cases, Durum wraps may also be used. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>humor</category>
      <category>computerscience</category>
      <category>datastructures</category>
      <category>googleinterviewquestions</category>
    </item>
    <item>
      <title>How did you estimate your coding experience level for dev.to?</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Tue, 31 Mar 2020 20:43:09 +0000</pubDate>
      <link>https://dev.to/brettimus/how-did-you-estimate-your-coding-experience-level-for-dev-to-16df</link>
      <guid>https://dev.to/brettimus/how-did-you-estimate-your-coding-experience-level-for-dev-to-16df</guid>
      <description>&lt;p&gt;I'm curious: How did others feel about evaluating their experience level inside their dev.to profile?&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;I'll be honest about something that I feel kind of weird about... I just set mine to 5, &lt;strong&gt;the max ooOOOoOoO&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Do I &lt;em&gt;really&lt;/em&gt; feel like "la crème de la crème" of engineers? Like a 5 out of 5?? Like a 5x dev?!? No. Absolutely not.&lt;/p&gt;

&lt;p&gt;However, I wanted to start seeing more challenging content in my feed, and I figured that would be the most straightforward way.&lt;/p&gt;

&lt;p&gt;Hence, I'm curious if anyone else felt unsure about how they estimated their skill-level.&lt;/p&gt;

&lt;p&gt;Opening the floor to discussion. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f56rtgfW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k8bezru02xri8ap63njw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f56rtgfW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k8bezru02xri8ap63njw.png" alt="Photo of the Content Customization section of UX Settings page"&gt;&lt;/a&gt;&lt;/p&gt;
This is what Content Customization looks like as of 31 March, 2020






&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;If you have no idea what I'm talking about, go to your &lt;a href="https://dev.to/settings/ux"&gt;UX Settings&lt;/a&gt; and scroll to &lt;strong&gt;Content Customization&lt;/strong&gt;.  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>discuss</category>
      <category>selfevaluation</category>
      <category>devmeta</category>
    </item>
    <item>
      <title>My COVID-proof /etc/hosts file</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Fri, 27 Mar 2020 18:20:13 +0000</pubDate>
      <link>https://dev.to/brettimus/my-covid-proof-etc-hosts-file-5c6k</link>
      <guid>https://dev.to/brettimus/my-covid-proof-etc-hosts-file-5c6k</guid>
      <description>&lt;p&gt;There's a point at which the news ceases to serve you, and only feeds the part of your brain that wants to reduce uncertainty. &lt;/p&gt;

&lt;p&gt;I have reached that point.&lt;/p&gt;

&lt;p&gt;Unfortunately, the world is extremely uncertain right now. And I just gotta learn to live with that.&lt;/p&gt;

&lt;p&gt;First, though, I wanted to break the habit of checking the news as often as I was. I figured I could, in the short term, block the news-related sites that were distracting me most often, e.g.: Twitter, The New York Times, and The Washington Post.&lt;/p&gt;

&lt;p&gt;To block these sites, I reached for an age-old trick: Modifying &lt;code&gt;/etc/hosts&lt;/code&gt; to map certain urls to localhost (example below).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
# TO STAY FOCUSED
127.0.0.1 twitter.com
127.0.0.1 www.twitter.com
127.0.0.1 mobile.twitter.com
127.0.0.1 www.mobile.twitter.com
127.0.0.1 nytimes.com
127.0.0.1 www.nytimes.com
127.0.0.1 washingtonpost.com
127.0.0.1 www.washingtonpost.com

255.255.255.255 broadcasthost
::1             localhost
# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, instead of the stream of "holy sh*t" headlines I was checking every hour, I now see (&lt;em&gt;pardon the Dutch&lt;/em&gt; 🇳🇱):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fog11a9iv4c0cmrfih4vk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fog11a9iv4c0cmrfih4vk.png" title="This is what you'll see, except probably not in Dutch" alt="nytimes.com shows no server connection possible" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;
This is what you'll see, except probably not in Dutch 🇳🇱



&lt;p&gt;Works like a charm!&lt;/p&gt;

&lt;p&gt;If, like me, you're on a Mac, you'll want to run &lt;code&gt;sudo killall -HUP mDNSResponder&lt;/code&gt; afterward editing &lt;code&gt;/etc/hosts&lt;/code&gt; in order to flush your DNS cache.&lt;/p&gt;

&lt;p&gt;Also, I should note that &lt;em&gt;messing up this file can have bad consequences&lt;/em&gt;... so make a copy before you toy with it, okay?&lt;/p&gt;

&lt;p&gt;Otherwise, stay inside and enjoy your weekend.&lt;/p&gt;

&lt;p&gt;✌️&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Also, as a post script, I should mention that my new deal with myself is only to check this &lt;a href="https://www.axios.com/coronavirus-latest-developments-8b8990c4-6762-494a-8ee0-5091746bda9b.html" rel="noopener noreferrer"&gt;Axios one-pager&lt;/a&gt; on pandemic updates. We'll see how that goes.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>focus</category>
      <category>coronavirus</category>
    </item>
    <item>
      <title>"Wikipedia Races, But For GitHub!" ... Is this a genius idea?</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Fri, 20 Mar 2020 02:33:05 +0000</pubDate>
      <link>https://dev.to/brettimus/wikipedia-races-but-for-github-is-this-a-genius-idea-55mo</link>
      <guid>https://dev.to/brettimus/wikipedia-races-but-for-github-is-this-a-genius-idea-55mo</guid>
      <description>&lt;p&gt;I was thinking some thoughts today, and a random memory came to mind.&lt;/p&gt;

&lt;p&gt;Many moons ago, two of my friends started a podcast where they would record themselves doing so-called "Wikipedia Races."&lt;/p&gt;

&lt;p&gt;If this is a new term for you, then you should know that a Wikipedia Race refers to a game in which you take two wildly divergent wikipedia pages, and you then try to navigate from one to the other.&lt;/p&gt;

&lt;p&gt;The twist is that you're only allowed to navigate using links to other wiki pages. No search. No crawlers. Just good, ole-fashioned hyperlink-clickin' fun!&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Aside: It hit me while I was typing out the rules that &lt;strong&gt;this game is just thinly veiled breadth-first search for humans.&lt;/strong&gt; Hah!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As an example, try starting from &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Spider-Man_3" rel="noopener noreferrer"&gt;Spider-Man 3&lt;/a&gt;&lt;/strong&gt; and maneuvering yourself to the page on &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Poland%E2%80%93United_States_relations" rel="noopener noreferrer"&gt;Poland-US Relations&lt;/a&gt;&lt;/strong&gt;. There's a very intuitive solution if you think about it!&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The reason I bring this up is that, after thinking of Wikiraces, a truly profound thought&lt;sup id="fnref3"&gt;3&lt;/sup&gt; entered my mind, which was: "&lt;strong&gt;Couldn't you do a Wikipedia Race on GitHub?&lt;/strong&gt; Or on GitHub's new bff, NPM?? What if you tried to race from one repo to another???"&lt;/p&gt;

&lt;p&gt;I paused for a second, and before any much-needed critical reflection could begin, I thought to myself, "Yeah! Sounds awesome! Why not?!" and I set out to tell the world about this awesome new game.&lt;/p&gt;

&lt;p&gt;I originally had two questions for the DEV community, which you're still free to answer if you want:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Would you ever play this game?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What would be some good combinations of projects&lt;/strong&gt; that I could try to race between on GitHub?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the thing is, after having written all of this down and thought about it for maybe six or seven more seconds, I'm not entirely sure if this somehow nerdier adaptation of Wikipedia Races actually sounds all-too fun.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Just think about the ways you'd have to navigate between repos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-project mentions (in issues, PRs, comments, etc)&lt;/li&gt;
&lt;li&gt;Users, via their interactions (contributions, stars, etc)&lt;/li&gt;
&lt;li&gt;A dependency graph, if it exists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Indiscriminately clicking through GitHub users just doesn't seem as fun as a random walk through Wikipedia articles. In fact, "fun" might be an inappropriate description for either of those activities. &lt;/p&gt;

&lt;p&gt;That said, even though a GitHub Race is sounding less "fun" by the moment, it just so happens that I am more or less stuck in my apartment for the foreseeable future.&lt;/p&gt;

&lt;p&gt;In addition to that, I'm noting that I just wrote a post about how excited I was to have thought up a game that I'm now almost sure would be exceedingly boring.&lt;/p&gt;

&lt;p&gt;So, I guess if current trends continue, my threshold for "fun" may drop dramatically over the next few days.&lt;/p&gt;

&lt;p&gt;In which case, do not be surprised if when I announce my innovative, new tech podcast next week 😁&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;My research tells me this is how people did Internet in the 90s. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;So intuitive! &lt;code&gt;Spider-Man 3 =&amp;gt; James Franco =&amp;gt; The Interview =&amp;gt; CIA =&amp;gt; Poland-United States Relations&lt;/code&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Okay yeah I didn't really check if someone already thought of this. It seems very likely that someone has already thought of this. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;You don't seem surprised? &lt;em&gt;Why don't you seem surprised???&lt;/em&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>discuss</category>
      <category>github</category>
      <category>npm</category>
      <category>game</category>
    </item>
    <item>
      <title>What would you name a read-only user role?</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Thu, 12 Mar 2020 15:09:28 +0000</pubDate>
      <link>https://dev.to/brettimus/what-would-you-name-a-read-only-user-role-5cng</link>
      <guid>https://dev.to/brettimus/what-would-you-name-a-read-only-user-role-5cng</guid>
      <description>&lt;p&gt;Assuming you implemented a role-based access control system, what would you name a "readonly" role?&lt;/p&gt;

&lt;p&gt;Here are my proposals so far, preference-ordered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Observer
* Spectator
* Monitor
* Watcher
* Reporter
* Guest
* Rubbernecker
* Greg
* Wallflower
* Mall-Cop
* Tattle-Tale
* Sloth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>discuss</category>
    </item>
    <item>
      <title>A countdown clock? In an email?? In this economy?!</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Tue, 10 Mar 2020 09:08:52 +0000</pubDate>
      <link>https://dev.to/brettimus/a-countdown-clock-in-an-email-in-this-economy-39h2</link>
      <guid>https://dev.to/brettimus/a-countdown-clock-in-an-email-in-this-economy-39h2</guid>
      <description>&lt;p&gt;Yesterday, I got an email from Memrise, a popular language learning tool.&lt;/p&gt;

&lt;p&gt;The email had an animated countdown clock in it, which unfortunately I didn't think to capture with a screen recorder. Nevertheless, here is what it looks like now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxpf3id7nedredm1s8ae3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxpf3id7nedredm1s8ae3.png" alt="Memrise Email Countdown Clock" width="578" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having worked on HTML emails in the past, I was impressed.&lt;/p&gt;

&lt;p&gt;Email is the Wild West of web development. Best practices for email would make most of us cry. You can never use javascript, you have to do layouts with tables, and most of your fancy CSS just won't work.&lt;/p&gt;

&lt;p&gt;I wanted to know how they did this countdown magic.&lt;/p&gt;

&lt;p&gt;First, I notice that the countdown clock was an image. Duh. It had to be!&lt;/p&gt;

&lt;p&gt;So then I followed the source of the image and saw it was a url without a file extension. I.e., there was no &lt;code&gt;.png&lt;/code&gt; or &lt;code&gt;.jpeg&lt;/code&gt; at the end of the url. It was just &lt;code&gt;https://gen.sendtric.com/countdown/zkihae5gaj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I opened this url and inspected the headers to see what was going on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
Pragma: no-cache
Content-Type: image/gif
Transfer-Encoding: Identity
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0
ETag: 14126387014612041038
Date: Tue, 10 Mar 2020 08:51:54 GMT
Content-Encoding: gzip
Expires: -1
Vary: Accept-Encoding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right! It's a gif.&lt;/p&gt;

&lt;p&gt;But... how'd they get the gif to work like a countdown?&lt;/p&gt;

&lt;p&gt;This part is just guesswork, but I'd imagine that this endpoint programmatically sends back a non-looping gif depending on the server time.&lt;/p&gt;

&lt;p&gt;That is, the server calculates how many seconds are left until Memrise's sale finishes, then it sends back a gif that animates a new frame every second, starting from the time until sale expires and finishing at &lt;code&gt;00:00:00:00&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, when I download and inspect the gif, it is only one frame, &lt;code&gt;00:00:00:00&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I wish I had time to try to recreate this... but unfortunately, I just got to work!&lt;/p&gt;

&lt;p&gt;If you have an alternative theory about how this magical countdown clock works, I'd love to hear it in the comments 😀&lt;/p&gt;

</description>
      <category>email</category>
    </item>
    <item>
      <title>How should you label boolean columns in a user-facing table?</title>
      <dc:creator>Boots</dc:creator>
      <pubDate>Thu, 05 Mar 2020 09:16:35 +0000</pubDate>
      <link>https://dev.to/brettimus/how-should-you-label-boolean-columns-in-a-user-facing-table-4oih</link>
      <guid>https://dev.to/brettimus/how-should-you-label-boolean-columns-in-a-user-facing-table-4oih</guid>
      <description>&lt;p&gt;I'm having one of those mornings where I'm questioning all the things.&lt;/p&gt;

&lt;p&gt;I prototyped a table where a boolean column was labeled with "Has Alert." This means the row is associated with an action item.&lt;/p&gt;

&lt;p&gt;I'm the only native English speaker at my job, and this label looked funny to my colleagues. Now it looks funny to me!&lt;/p&gt;

&lt;p&gt;I started to think about boolean columns, and I reasoned that there are broadly two types, those of Being and those of Existence&lt;sup id="fnref1"&gt;1&lt;/sup&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Being&lt;/code&gt;: The row "is" or "is not" a certain way&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Existence&lt;/code&gt;: The row "has" or "does not have" a property&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Being columns I usually omit the "is" in the label. E.g., if something can "be finished," I'd just write "Finished" in the column header.&lt;/p&gt;

&lt;p&gt;For Existence columns, I'm not so sure. I thus invite you to overthink this with me 😁&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How would &lt;em&gt;you&lt;/em&gt; label an existence column? What feels natural to you?&lt;/strong&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;I don't desire his approval, but I feel like &lt;a href="https://www.marxists.org/reference/subject/philosophy/works/ge/heidegg2.htm" rel="noopener noreferrer"&gt;Heidegger&lt;/a&gt; would be proud of this classification ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>discuss</category>
      <category>ui</category>
      <category>tables</category>
    </item>
  </channel>
</rss>
