<?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: Oleksii Trekhleb</title>
    <description>The latest articles on DEV Community by Oleksii Trekhleb (@trekhleb).</description>
    <link>https://dev.to/trekhleb</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%2F75714%2Fb0158eeb-ee34-4382-9afd-ca9f9bede62c.JPG</url>
      <title>DEV Community: Oleksii Trekhleb</title>
      <link>https://dev.to/trekhleb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/trekhleb"/>
    <language>en</language>
    <item>
      <title>I built a small app called CaliVibe to explore California counties and cities through data</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Fri, 13 Mar 2026 20:34:09 +0000</pubDate>
      <link>https://dev.to/trekhleb/i-built-a-small-app-called-calivibe-to-explore-california-counties-and-cities-through-data-37hc</link>
      <guid>https://dev.to/trekhleb/i-built-a-small-app-called-calivibe-to-explore-california-counties-and-cities-through-data-37hc</guid>
      <description>&lt;p&gt;Sometimes it is easier to understand a place through &lt;strong&gt;data&lt;/strong&gt; rather than descriptions.&lt;/p&gt;

&lt;p&gt;So I built a small interactive app that lets you explore &lt;strong&gt;California counties and cities&lt;/strong&gt; using different metrics like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;population&lt;/li&gt;
&lt;li&gt;crime rates&lt;/li&gt;
&lt;li&gt;temperature trends&lt;/li&gt;
&lt;li&gt;topographical landscape&lt;/li&gt;
&lt;li&gt;and other geographic data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try it here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://trekhleb.dev/cali-vibe/" rel="noopener noreferrer"&gt;https://trekhleb.dev/cali-vibe/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project is also open-sourced:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/trekhleb/cali-vibe" rel="noopener noreferrer"&gt;https://github.com/trekhleb/cali-vibe&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo (.gif)
&lt;/h2&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%2Fciwzx0auv9pxjjeihlx0.gif" 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%2Fciwzx0auv9pxjjeihlx0.gif" alt="CaliVibe GIF demo" width="560" height="313"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What you can explore
&lt;/h2&gt;

&lt;p&gt;The app lets you quickly switch between different datasets and see how regions compare.&lt;/p&gt;

&lt;p&gt;For example you can explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Population distribution&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Crime statistics&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Temperature trends&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terrain elevation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each dataset can reveal interesting patterns across California counties and cities.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example views
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Terrain view
&lt;/h3&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%2Fysdzihdc6com745ykkzn.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%2Fysdzihdc6com745ykkzn.png" alt="Terrain view" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Temperature trends
&lt;/h3&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%2F2d06mtwbaryvjruzwkw4.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%2F2d06mtwbaryvjruzwkw4.png" alt="Temperature trends" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Crime rates per city/county
&lt;/h3&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%2F1hodu5j0hx4uc89i2ntu.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%2F1hodu5j0hx4uc89i2ntu.png" alt="Crime rates per city/county" width="800" height="490"&gt;&lt;/a&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%2Fuploads%2Farticles%2Fvwceqef50uan500l2yva.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%2Fvwceqef50uan500l2yva.png" alt="Tabular view of a crime rates per city/county" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  County population
&lt;/h3&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%2Fqushx724m1ad6um1ibm0.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%2Fqushx724m1ad6um1ibm0.png" alt="County population" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  County/city borders
&lt;/h3&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%2Fvq0a852h41wfcexpelwb.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%2Fvq0a852h41wfcexpelwb.png" alt="County/city borders" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tech stack
&lt;/h2&gt;

&lt;p&gt;The app is intentionally simple and fully client-side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Visualization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MapLibre GL&lt;/li&gt;
&lt;li&gt;Three.js&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Data&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON datasets loaded as static assets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means the app runs &lt;strong&gt;without a backend&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data sources
&lt;/h2&gt;

&lt;p&gt;Some of the data used in the project comes from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CA DOJ OpenJustice&lt;/li&gt;
&lt;li&gt;California Department of Finance&lt;/li&gt;
&lt;li&gt;US Census Bureau&lt;/li&gt;
&lt;li&gt;Open-Meteo climate datasets&lt;/li&gt;
&lt;li&gt;Terrain tiles from AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The processed datasets are included in the repository.&lt;/p&gt;




&lt;h2&gt;
  
  
  Development experiment
&lt;/h2&gt;

&lt;p&gt;Another interesting aspect of this project is that it was mostly &lt;strong&gt;AI-assisted development&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I vibe-coded for fun: &lt;code&gt;~98%&lt;/code&gt; of the code was written by &lt;code&gt;Claude Code Opus&lt;/code&gt; with a few sprinkles from &lt;code&gt;Gemini 3.1 Pro&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This made it possible to move from idea → working prototype very quickly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;I enjoy building small interactive tools that help explore data visually.&lt;/p&gt;

&lt;p&gt;Sometimes a &lt;strong&gt;map + a few sliders&lt;/strong&gt; can reveal patterns much faster than tables or reports.&lt;/p&gt;

&lt;p&gt;This project was mostly a weekend experiment, but it turned into a fun way to explore California through data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;If you're curious how it works internally:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/trekhleb/cali-vibe" rel="noopener noreferrer"&gt;https://github.com/trekhleb/cali-vibe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback, ideas, and improvements are welcome.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>showdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Tech Jobs Radar</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Fri, 10 Jan 2025 16:02:52 +0000</pubDate>
      <link>https://dev.to/trekhleb/tech-jobs-radar-2nn9</link>
      <guid>https://dev.to/trekhleb/tech-jobs-radar-2nn9</guid>
      <description>&lt;p&gt;I was curious about the geographical distribution of top tech jobs—for example, how many FAANG jobs are in Europe and where they are primarily concentrated. To explore this, I created a draft (prototype) of Tech Jobs Radar: &lt;a href="https://jobs-radar.com" rel="noopener noreferrer"&gt;https://jobs-radar.com&lt;/a&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%2Fuploads%2Farticles%2Fxdm902vx09np6edx5kse.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%2Fxdm902vx09np6edx5kse.png" alt=" " width="800" height="489"&gt;&lt;/a&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%2Fuploads%2Farticles%2Fm4hwmgxbacdhypgpx36m.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%2Fm4hwmgxbacdhypgpx36m.png" alt=" " width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The platform visualizes a snapshot of open top tech positions on a map (currently based on December 2024 data). To make comparisons easier, it aggregates jobs into clusters depending on the zoom level, allowing you to analyze data across continents, countries, states, or counties.&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%2Fn9hrjvtir3610f37zgt8.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%2Fn9hrjvtir3610f37zgt8.png" alt=" " width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It also includes company and country filters to help you explore specific slices of the data—for instance, you can check open positions at Uber or identify the main engineering hubs for a particular company.&lt;/p&gt;

&lt;p&gt;Additionally, you can search for jobs by title. Each listing includes a link to the detailed description on Indeed.&lt;/p&gt;

&lt;p&gt;I’m sharing it here in case others are also curious about analyzing this kind of data.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>career</category>
    </item>
    <item>
      <title>An exploration of how X's home timeline API is designed</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Thu, 12 Dec 2024 19:56:20 +0000</pubDate>
      <link>https://dev.to/trekhleb/an-exploration-of-how-xs-home-timeline-api-is-designed-3n6o</link>
      <guid>https://dev.to/trekhleb/an-exploration-of-how-xs-home-timeline-api-is-designed-3n6o</guid>
      <description>&lt;p&gt;When it comes to designing the API of the system the software engineers often consider different options like &lt;a href="https://okso.app/showcase/system-design/page/0d03d895-b5b1-40c6-3549-945df9d98dcd" rel="noopener noreferrer"&gt;REST vs RPC vs GraphQL&lt;/a&gt; (or other hybrid approaches) to determine the best fit for a specific task or project.&lt;/p&gt;

&lt;p&gt;In this article, we explore how the &lt;strong&gt;X&lt;/strong&gt; (&lt;strong&gt;Twitter&lt;/strong&gt;) home timeline (x.com/home) API is designed and what approaches they use to solve the following challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to fetch the list of tweets&lt;/li&gt;
&lt;li&gt;How to do a sorting and pagination&lt;/li&gt;
&lt;li&gt;How to return the hierarchical/linked entities (tweets, users, media)&lt;/li&gt;
&lt;li&gt;How to get tweet details&lt;/li&gt;
&lt;li&gt;How to "like" a tweet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will only explore these challenges on the API level, treating the backend implementation as a black box, since we don't have access to the backend code itself.&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%2Fnlu70f1d34ijw7hhu1mw.jpg" 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%2Fnlu70f1d34ijw7hhu1mw.jpg" alt="X home timeline Example" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Showing the exact requests and responses here might be cumbersome and hard to follow since the deeply nested and repetitive objects are hard to read. To make it easier to see the request/response payload structure, I've made my attempt to "type out" the home timeline API in TypeScript. So when it comes to the request/response examples I'll use the request and response &lt;strong&gt;types&lt;/strong&gt; instead of actual JSON objects. Also, remember that the types are simplified and many properties are omitted for brevity.&lt;/p&gt;

&lt;p&gt;You may find all types in &lt;a href="https://github.com/trekhleb/trekhleb.github.io/blob/master/src/posts/2024/api-design-x-home-timeline/types/x.ts" rel="noopener noreferrer"&gt;types/x.ts&lt;/a&gt; file or at the bottom of this article in the "Appendix: All types in one place" section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Fetching the list of tweets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The endpoint and request/response structure
&lt;/h3&gt;

&lt;p&gt;Fetching the list of tweets for the home timeline starts with the &lt;code&gt;POST&lt;/code&gt; request to the following endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST https://x.com/i/api/graphql/{query-id}/HomeTimeline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a simplified &lt;strong&gt;request&lt;/strong&gt; body type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;queryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 's6ERr1UxkxxBx4YundNsXw'&lt;/span&gt;
  &lt;span class="nl"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 20&lt;/span&gt;
    &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'DAAACgGBGedb3Vx__9sKAAIZ5g4QENc99AcAAwAAIAIAAA'&lt;/span&gt;
    &lt;span class="nl"&gt;seenTweetIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// ['1867041249938530657', '1867041249938530659']&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Features&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="nx"&gt;Features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;articles_preview_enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;view_counts_everywhere_api_enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;And here is a simplified &lt;strong&gt;response&lt;/strong&gt; body type (we'll dive deeper into the response sub-types below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;home_timeline_urt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineTerminateTimeline&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt;
        &lt;span class="nl"&gt;responseObjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;feedbackActions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineAction&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="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="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineAddEntries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&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="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'tweet-1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1866561576636152411'&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;itemContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;feedbackInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;feedbackKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// ['-1378668161']&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;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTweet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tweet_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Tweet&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;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'cursor-top-1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1866961576813152212'&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineCursor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'DACBCgABGedb4VyaJwuKbIIZ40cX3dYwGgaAAwAEAEEAA'&lt;/span&gt;
    &lt;span class="nl"&gt;cursorType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Top&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bottom&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;type&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is interesting to note here, that "getting" the data is done via "POSTing", which is not common for the REST-like API but it is common for a GraphQL-like API. Also, the &lt;code&gt;graphql&lt;/code&gt; part of the URL indicates that X is using the GraphQL flavor for their API.&lt;/p&gt;

&lt;p&gt;I'm using the word &lt;em&gt;"flavor"&lt;/em&gt; here because the request body itself doesn't look like a pure &lt;a href="https://graphql.org/learn/queries/" rel="noopener noreferrer"&gt;GraphQL query&lt;/a&gt;, where we may describe the required response structure, listing all the properties we want to fetch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="c"&gt;# An example of a pure GraphQL request structure that is *not* being used in the X API.&lt;/span&gt;&lt;span class="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;tweets&lt;/span&gt;&lt;span class="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;id&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;medias&lt;/span&gt;&lt;span class="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;kind&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c"&gt;# ...&lt;/span&gt;&lt;span class="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;author&lt;/span&gt;&lt;span class="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;id&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="c"&gt;# ...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c"&gt;# ...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The assumption here is that the home timeline API is not a pure GraphQL API, but is a &lt;strong&gt;mix of several approaches&lt;/strong&gt;. Passing the parameters in a POST request like this seems closer to the "functional" RPC call. But at the same time, it seems like the GraphQL features might be used somewhere on the backend behind the &lt;em&gt;HomeTimeline&lt;/em&gt; endpoint handler/controller. A mix like this might also be caused by a legacy code or some sort of ongoing migration. But again, these are just my speculations.&lt;/p&gt;

&lt;p&gt;You may also notice that the same &lt;code&gt;TimelineRequest.queryId&lt;/code&gt; is used in the API URL as well as in the API request body. This queryId is most probably generated on the backend, then it gets embedded in the &lt;code&gt;main.js&lt;/code&gt; bundle, and then it is used when fetching the data from the backend. It is hard for me to understand how this &lt;code&gt;queryId&lt;/code&gt; is used exactly since X's backend is a black box in our case. But, again, the speculation here might be that, it might be needed for some sort of performance optimization (re-using some pre-computed query results?), caching (Apollo related?), debugging (join logs by queryId?), or tracking/tracing purposes.&lt;/p&gt;

&lt;p&gt;It is also interesting to note, that the &lt;code&gt;TimelineResponse&lt;/code&gt; contains not a list of tweets, but rather a list of &lt;strong&gt;instructions&lt;/strong&gt;, like &lt;em&gt;"add a tweet to the timeline"&lt;/em&gt; (see the &lt;code&gt;TimelineAddEntries&lt;/code&gt; type), or &lt;em&gt;"terminate the timeline"&lt;/em&gt; (see the &lt;code&gt;TimelineTerminateTimeline&lt;/code&gt; type).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TimelineAddEntries&lt;/code&gt; instruction itself may also contain different types of entities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tweets — see the &lt;code&gt;TimelineItem&lt;/code&gt; type&lt;/li&gt;
&lt;li&gt;Cursors — see the &lt;code&gt;TimelineCursor&lt;/code&gt; type&lt;/li&gt;
&lt;li&gt;Conversations/comments/threads — see the &lt;code&gt;TimelineModule&lt;/code&gt; type
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;home_timeline_urt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineTerminateTimeline&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here&lt;/span&gt;
        &lt;span class="c1"&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineAddEntries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is interesting from the extendability point of view since it allows a wider variety of what can be rendered in the home timeline without tweaking the API too much.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pagination
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;TimelineRequest.variables.count&lt;/code&gt; property sets how many tweets we want to fetch at once (per page). The default is 20. However, more than 20 tweets can be returned in the &lt;code&gt;TimelineAddEntries.entries&lt;/code&gt; array. For example, the array might contain 37 entries for the first page load, because it includes tweets (29), pinned tweets (1), promoted tweets (5), and pagination cursors (2). I'm not sure why there are  29 regular tweets with the requested count of 20 though.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TimelineRequest.variables.cursor&lt;/code&gt; is responsible for the cursor-based pagination.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"&lt;strong&gt;Cursor pagination&lt;/strong&gt; is most often used for real-time data due to the frequency new records are added and because when reading data you often see the latest results first. It eliminates the possibility of skipping items and displaying the same item more than once. In cursor-based pagination, a constant pointer (or cursor) is used to keep track of where in the data set the next items should be fetched from." See the &lt;a href="https://stackoverflow.com/questions/55744926/offset-pagination-vs-cursor-pagination" rel="noopener noreferrer"&gt;Offset pagination vs Cursor pagination&lt;/a&gt; thread for the context.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When fetching the list of tweets for the first time the &lt;code&gt;TimelineRequest.variables.cursor&lt;/code&gt; is empty, since we want to fetch the top tweets from the default (most probably pre-computed) list of personalized tweets.&lt;/p&gt;

&lt;p&gt;However, in the response, along with the tweet data, the backend also returns the cursor entries. Here is the response type hierarchy: &lt;code&gt;TimelineResponse → TimelineAddEntries → TimelineCursor&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;home_timeline_urt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineTerminateTimeline&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here&lt;/span&gt;
        &lt;span class="c1"&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineAddEntries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here (tweets + cursors)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineCursor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'DACBCgABGedb4VyaJwuKbIIZ40cX3dYwGgaAAwAEAEEAA' &amp;lt;-- Here&lt;/span&gt;
    &lt;span class="nl"&gt;cursorType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Top&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bottom&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every page contains the list of tweets along with "top" and "bottom" cursors:&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%2F1pr264quw4fb3iike9ui.jpg" 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%2F1pr264quw4fb3iike9ui.jpg" alt="Cursors" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the page data is loaded, we can go from the current page in both directions and fetch either the "previous/older" tweets using the "bottom" cursor or the "next/newer" tweets using the "top" cursor. My assumption is that fetching the "next" tweets using the "top" cursor happens in two cases: when the new tweets were added while the user is still reading the current page, or when the user starts scrolling the feed upwards (and there are no cached entries or if the previous entries were deleted for the performance reasons).&lt;/p&gt;

&lt;p&gt;The X's cursor itself might look like this: &lt;code&gt;DAABCgABGemI6Mk__9sKAAIZ6MSYG9fQGwgAAwAAAAIAAA&lt;/code&gt;. In some API designs, the cursor may be a Base64 encoded string that contains the id of the last entry in the list, or the timestamp of the last seen entry. For example: &lt;code&gt;eyJpZCI6ICIxMjM0NTY3ODkwIn0= --&amp;gt; {"id": "1234567890"}&lt;/code&gt;, and then, this data is used to query the database accordingly. In the case of X API, it looks like the cursor is being Base64 decoded into some custom binary sequence that might require some further decoding to get any meaning out of it (i.e. via the Protobuf message definitions). Since we don't know if it is a &lt;code&gt;.proto&lt;/code&gt; encoding and also we don't know the &lt;code&gt;.proto&lt;/code&gt; message definition we may just assume that the backend knows how to query the next batch of tweets based on the cursor string.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TimelineResponse.variables.seenTweetIds&lt;/code&gt; parameter is used to inform the server about which tweets from the currently active page of the infinite scrolling the client has already seen. This most probably helps ensure that the server does not include duplicate tweets in subsequent pages of results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linked/hierarchical entities
&lt;/h2&gt;

&lt;p&gt;One of the challenges to be solved in the APIs like home timeline (or Home Feed) is to figure out how to return the linked or hierarchical entities (i.e. &lt;code&gt;tweet → user&lt;/code&gt;, &lt;code&gt;tweet → media&lt;/code&gt;, &lt;code&gt;media → author&lt;/code&gt;, etc):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should we only return the list of tweets first and then fetch the dependent entities (like user details) in a bunch of separate queries on-demand?&lt;/li&gt;
&lt;li&gt;Or should we return all the data at once, increasing the time and the size of the first load, but saving the time for all subsequent calls?

&lt;ul&gt;
&lt;li&gt;Do we need to normalize the data in this case to reduce the payload size (i.e. when the same user is an author of many tweets and we want to avoid repeating the user data over and over again in each tweet entity)?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Or should it be a combination of the approaches above?&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Let's see how X handles it.&lt;/p&gt;

&lt;p&gt;Earlier in the &lt;code&gt;TimelineTweet&lt;/code&gt; type the &lt;code&gt;Tweet&lt;/code&gt; sub-type was used. Let's see how it looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;home_timeline_urt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineTerminateTimeline&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here&lt;/span&gt;
        &lt;span class="c1"&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineAddEntries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;itemContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here&lt;/span&gt;
    &lt;span class="c1"&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;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTweet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tweet_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Tweet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// A Tweet entity&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tweet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;core&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;user_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here (a dependent User entity)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;legacy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;full_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nl"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here (a dependent Media entities)&lt;/span&gt;
      &lt;span class="na"&gt;media&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Media&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="nl"&gt;hashtags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Hashtag&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="nl"&gt;urls&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="nl"&gt;user_mentions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserMention&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="c1"&gt;// A User entity&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'VXNlcjoxNDUxM4ADSG44MTA4NDc4OTc2'&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="nl"&gt;legacy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'San Francisco'&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  'John Doe'&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// A Media entity&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Media&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;source_user_id_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'  &amp;lt;-- Here (the dependant user is being mentioned by its ID)&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://t.co/X78dBgtrsNU'&lt;/span&gt;
  &lt;span class="nl"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;large&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaceGeometry&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaceGeometry&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;small&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaceGeometry&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;orig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaceGeometry&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="nl"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;large&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;small&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;thumb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;video_info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VideoInfo&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;What's interesting here is that most of the dependent data like &lt;code&gt;tweet → media&lt;/code&gt; and &lt;code&gt;tweet → author&lt;/code&gt; is embedded into the response on the first call (no subsequent queries).&lt;/p&gt;

&lt;p&gt;Also, the &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Media&lt;/code&gt; connections with &lt;code&gt;Tweet&lt;/code&gt; entities are not normalized (if two tweets have the same author, their data will be repeated in each tweet object). But it seems like it should be ok, since in the scope of the home timeline for a specific user the tweets will be authored by many authors and repetitions are possible but sparse.&lt;/p&gt;

&lt;p&gt;My assumption was that the &lt;code&gt;UserTweets&lt;/code&gt; API (that we don't cover here), which is responsible for fetching the tweets of &lt;em&gt;one particular user&lt;/em&gt; will handle it differently, but, apparently, it is not the case. The &lt;code&gt;UserTweets&lt;/code&gt; returns the list of tweets of the same user and embeds the same user data over and over again for each tweet. It's interesting. Maybe the simplicity of the approach beats some data size overhead (maybe user data is considered pretty small in size). I'm not sure.&lt;/p&gt;

&lt;p&gt;Another observation about the entities' relationship is that the &lt;code&gt;Media&lt;/code&gt; entity also has a link to the &lt;code&gt;User&lt;/code&gt; (the author). But it does it not via direct entity embedding as the &lt;code&gt;Tweet&lt;/code&gt; entity does, but rather it links via the &lt;code&gt;Media.source_user_id_str&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;The "comments" (which are also the "tweets" by their nature) for each "tweet" in the home timeline are not fetched at all. To see the tweet thread the user must click on the tweet to see its detailed view. The tweet thread will be fetched by calling the &lt;code&gt;TweetDetail&lt;/code&gt; endpoint (more about it in the "Tweet detail page" section below).&lt;/p&gt;

&lt;p&gt;Another entity that each &lt;code&gt;Tweet&lt;/code&gt; has is &lt;code&gt;FeedbackActions&lt;/code&gt; (i.e. "Recommend less often" or "See fewer"). The way the &lt;code&gt;FeedbackActions&lt;/code&gt; are stored in the response object is different from the way the &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Media&lt;/code&gt; objects are stored. While the &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Media&lt;/code&gt; entities are part of the &lt;code&gt;Tweet&lt;/code&gt;, the &lt;code&gt;FeedbackActions&lt;/code&gt; are stored separately in &lt;code&gt;TimelineItem.content.feedbackInfo.feedbackKeys&lt;/code&gt; array and are linked via the &lt;code&gt;ActionKey&lt;/code&gt;. That was a slight surprise for me since it doesn't seem to be the case that any action is re-usable. It looks like one action is used for one particular tweet only. So it seems like the &lt;code&gt;FeedbackActions&lt;/code&gt; could be embedded into each tweet in the same way as &lt;code&gt;Media&lt;/code&gt; entities. But I might be missing some hidden complexity here (like the fact that each action can have children actions).&lt;/p&gt;

&lt;p&gt;More details about the actions are in the "Tweet actions" section below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sorting
&lt;/h2&gt;

&lt;p&gt;The sorting order of the timeline entries is defined by the backend via the &lt;code&gt;sortIndex&lt;/code&gt; properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1866961576813152212' &amp;lt;-- Here&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineCursor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cursorType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Top&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bottom&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;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1866561576636152411' &amp;lt;-- Here&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;itemContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;feedbackInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;feedbackKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '73343543020642838441' &amp;lt;-- Here&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineModule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}[],&lt;/span&gt;
    &lt;span class="na"&gt;displayType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VerticalConversation&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sortIndex&lt;/code&gt; itself might look something like this &lt;code&gt;'1867231621095096312'&lt;/code&gt;. It likely corresponds directly to or is derived from a &lt;a href="https://en.wikipedia.org/wiki/Snowflake_ID" rel="noopener noreferrer"&gt;Snowflake ID&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Actually most of the IDs you see in the response (tweet IDs) follow the "Snowflake ID" convention and look like &lt;code&gt;'1867231621095096312'&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If this is used to sort entities like tweets, the system leverages the inherent chronological sorting of Snowflake IDs. Tweets or objects with a higher sortIndex value (a more recent timestamp) appear higher in the feed, while those with lower values (an older timestamp) appear lower in the feed.&lt;/p&gt;

&lt;p&gt;Here’s the step-by-step decoding of the Snowflake ID (in our case the &lt;code&gt;sortIndex&lt;/code&gt;) &lt;code&gt;1867231621095096312&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extract the &lt;strong&gt;Timestamp&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The timestamp is derived by right-shifting the Snowflake ID by 22 bits (to remove the lower 22 bits for data center, worker ID, and sequence): &lt;code&gt;1867231621095096312 → 445182709954&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Add &lt;strong&gt;Twitter's Epoch&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Adding Twitter's custom epoch (1288834974657) to this timestamp gives the UNIX timestamp in milliseconds: &lt;code&gt;445182709954 + 1288834974657 → 1734017684611ms&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Convert to a &lt;strong&gt;human-readable date&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Converting the UNIX timestamp to a UTC datetime gives: &lt;code&gt;1734017684611ms → 2024-12-12 15:34:44.611 (UTC)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;So we can assume here that the tweets in the home timeline are sorted chronologically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tweet actions
&lt;/h2&gt;

&lt;p&gt;Each tweet has an "Actions" menu.&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%2Fs18opnpal6qawxkufhy4.jpg" 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%2Fs18opnpal6qawxkufhy4.jpg" alt="Actions" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The actions for each tweet are coming from the backend in a &lt;code&gt;TimelineItem.content.feedbackInfo.feedbackKeys&lt;/code&gt; array and are linked with the tweets via the &lt;code&gt;ActionKey&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;home_timeline_urt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineTerminateTimeline&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt;
        &lt;span class="nl"&gt;responseObjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;feedbackActions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineAction&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- Here&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="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;itemContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;feedbackInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;feedbackKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// ['-1378668161'] &amp;lt;-- Here&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;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '-609233128'&lt;/span&gt;
  &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;feedbackType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NotRelevant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DontLike&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SeeFewer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nl"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'This post isn’t relevant' | 'Not interested in this post' | ...&lt;/span&gt;
    &lt;span class="nl"&gt;confirmation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Thanks. You’ll see fewer posts like this.'&lt;/span&gt;
    &lt;span class="nl"&gt;childKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// ['1192182653', '-1427553257'], i.e. NotInterested -&amp;gt; SeeFewer&lt;/span&gt;
    &lt;span class="nl"&gt;feedbackUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '/2/timeline/feedback.json?feedback_type=NotRelevant&amp;amp;action_metadata=SRwW6oXZadPHiOczBBaAwPanEwE%3D'&lt;/span&gt;
    &lt;span class="nl"&gt;hasUndoAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Frown'&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;It is interesting here that this flat array of actions is actually a tree (or a graph? I didn't check), since each action may have child actions (see the &lt;code&gt;TimelineAction.value.childKeys&lt;/code&gt; array). This makes sense, for example, when after the user clicks on the &lt;strong&gt;"Don't Like"&lt;/strong&gt; action, the follow-up might be to show the &lt;strong&gt;"This post isn’t relevant"&lt;/strong&gt; action, as a way of explaining why the user doesn't like the tweet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tweet detail page
&lt;/h2&gt;

&lt;p&gt;Once the user would like to see the tweet detail page (i.e. to see the thread of comments/tweets), the user clicks on the tweet and the &lt;code&gt;GET&lt;/code&gt; request to the following endpoint is performed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET https://x.com/i/api/graphql/{query-id}/TweetDetail?variables={"focalTweetId":"1867231621095096312","referrer":"home","controller_data":"DACABBSQ","rankingMode":"Relevance","includePromotedContent":true,"withCommunity":true}&amp;amp;features={"articles_preview_enabled":true}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was curious here why the list of tweets is being fetched via the &lt;code&gt;POST&lt;/code&gt; call, but each tweet detail is fetched via the &lt;code&gt;GET&lt;/code&gt; call. Seems inconsistent. Especially keeping in mind that similar query parameters like &lt;code&gt;query-id&lt;/code&gt;, &lt;code&gt;features&lt;/code&gt;, and others this time are passed in the URL and not in the request body. The response format is also similar and is re-using the types from the list call. I'm not sure why is that. But again, I'm sure I might be might be missing some background complexity here.&lt;/p&gt;

&lt;p&gt;Here are the simplified response body types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TweetDetailResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;threaded_conversation_with_injections_v2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineTerminateTimeline&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineAddEntries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&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="nx"&gt;TimelineTerminateTimeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTerminateTimeline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Top&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'conversationthread-58668734545929871193'&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867231621095096312'&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineModule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 'conversationthread-1866876425669871193-tweet-1866876038930951193'&lt;/span&gt;
      &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}[],&lt;/span&gt; &lt;span class="c1"&gt;// Comments to the tweets are also tweets&lt;/span&gt;
    &lt;span class="na"&gt;displayType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VerticalConversation&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response is pretty similar (in its types) to the list response, so we won't for too long here.&lt;/p&gt;

&lt;p&gt;One interesting nuance is that the "comments" (or conversations) of each tweet are actually other tweets (see the &lt;code&gt;TimelineModule&lt;/code&gt; type). So the tweet thread looks very similar to the home timeline feed by showing the list of &lt;code&gt;TimelineTweet&lt;/code&gt; entries. This looks elegant. A good example of a universal and re-usable approach to the API design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Liking the tweet
&lt;/h2&gt;

&lt;p&gt;When a user likes the tweet, the &lt;code&gt;POST&lt;/code&gt; request to the following endpoint is being performed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST https://x.com/i/api/graphql/{query-id}/FavoriteTweet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the &lt;strong&gt;request&lt;/strong&gt; body types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FavoriteTweetRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;tweet_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;queryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'lI07N61twFgted2EgXILM7A'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the &lt;strong&gt;response&lt;/strong&gt; body types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FavoriteTweetResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;favorite_tweet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Done&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks straightforward and also resembles the RPC-like approach to the API design.&lt;/p&gt;

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

&lt;p&gt;We have touched on some basic parts of the home timeline API design by looking at X's API example. I made some assumptions along the way to the best of my knowledge. I believe some things I might have interpreted incorrectly and I might have missed some complex nuances. But even with that in mind, I hope you got some useful insights from this high-level overview, something that you could apply in your next API Design session.&lt;/p&gt;

&lt;p&gt;Initially, I had a plan to go through similar top-tech websites to get some insights from Facebook, Reddit, YouTube, and others and to collect battle-tested best practices and solutions. I'm not sure if I'll find the time to do that. Will see. But it could be an interesting exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appendix: All types in one place
&lt;/h2&gt;

&lt;p&gt;For the reference, I'm adding all types in one go here. You may also find all types in &lt;a href="https://github.com/trekhleb/trekhleb.github.io/blob/master/src/posts/2024/api-design-x-home-timeline/types/x.ts" rel="noopener noreferrer"&gt;types/x.ts&lt;/a&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * This file contains the simplified types for X's (Twitter's) home timeline API.
 *
 * These types are created for exploratory purposes, to see the current implementation
 * of the X's API, to see how they fetch Home Feed, how they do a pagination and sorting,
 * and how they pass the hierarchical entities (posts, media, user info, etc).
 *
 * Many properties and types are omitted for simplicity.
 */&lt;/span&gt;

&lt;span class="c1"&gt;// POST https://x.com/i/api/graphql/{query-id}/HomeTimeline&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;queryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 's6ERr1UxkxxBx4YundNsXw'&lt;/span&gt;
  &lt;span class="nl"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 20&lt;/span&gt;
    &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'DAAACgGBGedb3Vx__9sKAAIZ5g4QENc99AcAAwAAIAIAAA'&lt;/span&gt;
    &lt;span class="nl"&gt;seenTweetIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// ['1867041249938530657', '1867041249938530658']&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Features&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// POST https://x.com/i/api/graphql/{query-id}/HomeTimeline&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;home_timeline_urt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineTerminateTimeline&lt;/span&gt;&lt;span class="p"&gt;)[];&lt;/span&gt;
        &lt;span class="nl"&gt;responseObjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;feedbackActions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineAction&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="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// POST https://x.com/i/api/graphql/{query-id}/FavoriteTweet&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FavoriteTweetRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;tweet_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;queryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'lI07N6OtwFgted2EgXILM7A'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// POST https://x.com/i/api/graphql/{query-id}/FavoriteTweet&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FavoriteTweetResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;favorite_tweet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Done&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="c1"&gt;// GET https://x.com/i/api/graphql/{query-id}/TweetDetail?variables={"focalTweetId":"1867041249938530657","referrer":"home","controller_data":"DACABBSQ","rankingMode":"Relevance","includePromotedContent":true,"withCommunity":true}&amp;amp;features={"articles_preview_enabled":true}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TweetDetailResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;threaded_conversation_with_injections_v2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineTerminateTimeline&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;articles_preview_enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;view_counts_everywhere_api_enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '-609233128'&lt;/span&gt;
  &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;feedbackType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NotRelevant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DontLike&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SeeFewer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nl"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'This post isn’t relevant' | 'Not interested in this post' | ...&lt;/span&gt;
    &lt;span class="nl"&gt;confirmation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Thanks. You’ll see fewer posts like this.'&lt;/span&gt;
    &lt;span class="nl"&gt;childKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// ['1192182653', '-1427553257'], i.e. NotInterested -&amp;gt; SeeFewer&lt;/span&gt;
    &lt;span class="nl"&gt;feedbackUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '/2/timeline/feedback.json?feedback_type=NotRelevant&amp;amp;action_metadata=SRwW6oXZadPHiOczBBaAwPanEwE%3D'&lt;/span&gt;
    &lt;span class="nl"&gt;hasUndoAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Frown'&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="nx"&gt;TimelineAddEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineAddEntries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&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="nx"&gt;TimelineTerminateTimeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTerminateTimeline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Top&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineCursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'cursor-top-1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867231621095096312'&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineCursor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'DACBCgABGedb4VyaJwuKbIIZ40cX3dYwGgaAAwAEAEEAA'&lt;/span&gt;
    &lt;span class="nl"&gt;cursorType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Top&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bottom&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;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'tweet-1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867231621095096312'&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;itemContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;feedbackInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;feedbackKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// ['-1378668161']&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;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'conversationthread-1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;sortIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867231621095096312'&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTimelineModule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;entryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 'conversationthread-1867041249938530657-tweet-1867041249938530657'&lt;/span&gt;
      &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}[],&lt;/span&gt; &lt;span class="c1"&gt;// Comments to the tweets are also tweets&lt;/span&gt;
    &lt;span class="na"&gt;displayType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VerticalConversation&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;type&lt;/span&gt; &lt;span class="nx"&gt;TimelineTweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TimelineTweet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tweet_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Tweet&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;type&lt;/span&gt; &lt;span class="nx"&gt;Tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tweet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;core&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;user_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&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="nl"&gt;views&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '13763'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;legacy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bookmark_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 358&lt;/span&gt;
    &lt;span class="nl"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Tue Dec 10 17:41:28 +0000 2024'&lt;/span&gt;
    &lt;span class="nl"&gt;conversation_id_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
    &lt;span class="nl"&gt;display_text_range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// [0, 58]&lt;/span&gt;
    &lt;span class="nl"&gt;favorite_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 151&lt;/span&gt;
    &lt;span class="nl"&gt;full_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  "How I'd promote my startup, if I had 0 followers (Part 1)"&lt;/span&gt;
    &lt;span class="nl"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'en'&lt;/span&gt;
    &lt;span class="nl"&gt;quote_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;reply_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;retweet_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;user_id_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
    &lt;span class="nl"&gt;id_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
    &lt;span class="nl"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;media&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Media&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="nl"&gt;hashtags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Hashtag&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="nl"&gt;urls&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="nl"&gt;user_mentions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserMention&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;__typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'VXNlcjoxNDUxM4ADSG44MTA4NDc4OTc2'&lt;/span&gt;
  &lt;span class="nl"&gt;rest_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;is_blue_verified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;profile_image_shape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Circle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="nl"&gt;legacy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;following&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Thu Oct 21 09:30:37 +0000 2021'&lt;/span&gt;
    &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'I help startup founders double their MRR with outside-the-box marketing cheat sheets'&lt;/span&gt;
    &lt;span class="nl"&gt;favourites_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 22195&lt;/span&gt;
    &lt;span class="nl"&gt;followers_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 25658&lt;/span&gt;
    &lt;span class="nl"&gt;friends_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'San Francisco'&lt;/span&gt;
    &lt;span class="nl"&gt;media_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  'John Doe'&lt;/span&gt;
    &lt;span class="nl"&gt;profile_banner_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://pbs.twimg.com/profile_banners/4863509452891265813/4863509'&lt;/span&gt;
    &lt;span class="nl"&gt;profile_image_url_https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://pbs.twimg.com/profile_images/4863509452891265813/4863509_normal.jpg'&lt;/span&gt;
    &lt;span class="nl"&gt;screen_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'johndoe'&lt;/span&gt;
    &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://t.co/dgTEddFGDd'&lt;/span&gt;
    &lt;span class="nl"&gt;verified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;type&lt;/span&gt; &lt;span class="nx"&gt;Media&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;display_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'pic.x.com/X7823zS3sNU'&lt;/span&gt;
  &lt;span class="nl"&gt;expanded_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://x.com/johndoe/status/1867041249938530657/video/1'&lt;/span&gt;
  &lt;span class="nl"&gt;ext_alt_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Image of two bridges.'&lt;/span&gt;
  &lt;span class="nl"&gt;id_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// [93, 116]&lt;/span&gt;
  &lt;span class="nl"&gt;media_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '13_2866509231399826944'&lt;/span&gt;
  &lt;span class="nl"&gt;media_url_https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://pbs.twimg.com/profile_images/1867041249938530657/4863509_normal.jpg'&lt;/span&gt;
  &lt;span class="nl"&gt;source_status_id_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;source_user_id_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '1867041249938530657'&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'video'&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://t.co/X78dBgtrsNU'&lt;/span&gt;
  &lt;span class="nl"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;large&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaceGeometry&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaceGeometry&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;small&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaceGeometry&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;orig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaceGeometry&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="nl"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;large&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;small&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;thumb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;video_info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VideoInfo&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="nx"&gt;UserMention&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id_str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// '98008038'&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'Yann LeCun'&lt;/span&gt;
  &lt;span class="nl"&gt;screen_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'ylecun'&lt;/span&gt;
  &lt;span class="nl"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// [115, 122]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Hashtag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// [257, 263]&lt;/span&gt;
  &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;Url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;display_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'google.com'&lt;/span&gt;
  &lt;span class="nl"&gt;expanded_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'http://google.com'&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://t.co/nZh3aF0Aw6'&lt;/span&gt;
  &lt;span class="nl"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// [102, 125]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;VideoInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;aspect_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// [427, 240]&lt;/span&gt;
  &lt;span class="nl"&gt;duration_millis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 20000&lt;/span&gt;
  &lt;span class="nl"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bitrate&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 288000&lt;/span&gt;
    &lt;span class="nl"&gt;content_type&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'application/x-mpegURL' | 'video/mp4' | ...&lt;/span&gt;
    &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'https://video.twimg.com/amplify_video/18665094345456w6944/pl/-ItQau_LRWedR-W7.m3u8?tag=14'&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="nx"&gt;FaceGeometry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MediaSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActionKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>programming</category>
      <category>learning</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Homemade GPT JS</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Sun, 10 Nov 2024 17:41:44 +0000</pubDate>
      <link>https://dev.to/trekhleb/homemade-gpt-js-1c1c</link>
      <guid>https://dev.to/trekhleb/homemade-gpt-js-1c1c</guid>
      <description>&lt;p&gt;For learning purposes, I made a minimal TensorFlow.js re-implementation of Karpathy's &lt;a href="https://github.com/karpathy/minGPT" rel="noopener noreferrer"&gt;minGPT&lt;/a&gt; (Generative Pre-trained Transformer). &lt;/p&gt;

&lt;p&gt;A full definition of this "homemade" &lt;strong&gt;GPT&lt;/strong&gt; language model (all of it) can be found in this single &lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/model.ts" rel="noopener noreferrer"&gt;model.ts&lt;/a&gt; file (less than &lt;code&gt;300&lt;/code&gt; lines of code).&lt;/p&gt;

&lt;p&gt;Since &lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/model.ts" rel="noopener noreferrer"&gt;model.ts&lt;/a&gt; is written in TypeScript, you can use &lt;a href="https://trekhleb.dev/homemade-gpt-js" rel="noopener noreferrer"&gt;homemade GPT playground&lt;/a&gt; to train it, experiment with parameters, and generate its predictions directly in the browser using a GPU.&lt;/p&gt;

&lt;p&gt;The model and the playground are written for &lt;em&gt;learning purposes&lt;/em&gt;, to understand how GPT works and to use WebGPU for training.&lt;/p&gt;

&lt;p&gt;To understand what's happening in the &lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/model.ts" rel="noopener noreferrer"&gt;model.ts&lt;/a&gt; file please refer to Andrej Karpathy's well-explained, hands-on lecture "&lt;a href="https://www.youtube.com/watch?v=kCc8FmEb1nY" rel="noopener noreferrer"&gt;Let's build GPT: from scratch, in code, spelled out&lt;/a&gt;" (arguably one of the best explanations of GPT out there).&lt;/p&gt;

&lt;h3&gt;
  
  
  GPT Folder
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/" rel="noopener noreferrer"&gt;./gpt/src/&lt;/a&gt; folder you'll find the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/model.ts" rel="noopener noreferrer"&gt;model.ts&lt;/a&gt; - this is the main file of interest, as it contains the full (yet minimalistic) definition of the decoder GPT model, as described in the &lt;a href="https://arxiv.org/pdf/1706.03762" rel="noopener noreferrer"&gt;Attention Is All You Need&lt;/a&gt; paper.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/model-easier.ts" rel="noopener noreferrer"&gt;model-easier.ts&lt;/a&gt; - this is the same GPT model as in the previous file but simplified for easier understanding. The main difference is that it processes all &lt;code&gt;Heads&lt;/code&gt; inside &lt;code&gt;CausalSelfAttention&lt;/code&gt; &lt;em&gt;sequentially&lt;/em&gt; (instead of in parallel). As a result, the model is a bit slower but more readable.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/config.ts" rel="noopener noreferrer"&gt;config.ts&lt;/a&gt; - contains pre-configured sets of GPT model parameters: GPT-pico, GPT-nano, GPT-mini, GPT-2, etc.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/dataset.ts" rel="noopener noreferrer"&gt;dataset.ts&lt;/a&gt; - Nothing GPT-specific here. A helper wrapper on top of any txt-file-based character-level dataset. It loads an arbitrary txt file, treats each letter as a token, splits the characters into training and testing batches, and encodes/decodes letters to indices and vice versa.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/gpt/src/trainer.ts" rel="noopener noreferrer"&gt;trainer.ts&lt;/a&gt; - Nothing GPT-specific here as well. This file provides a simple training loop that could apply to any arbitrary neural network.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Web Playground
&lt;/h3&gt;

&lt;p&gt;To experiment with model parameters, training, and text generation you may use the &lt;a href="https://trekhleb.dev/homemade-gpt-js" rel="noopener noreferrer"&gt;Homemade GPT JS playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/WAdG5xmBSJk"&gt;
&lt;/iframe&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%2Fuploads%2Farticles%2Fqliqx70pkl0as7mzn4h8.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%2Fqliqx70pkl0as7mzn4h8.png" alt=" " width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may also launch the playground locally if you want to modify and experiment with the code of the transformer model itself.&lt;/p&gt;

&lt;p&gt;Install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch web playground locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run playground-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The playground will be accessible on &lt;a href="http://localhost:3000/homemade-gpt-js" rel="noopener noreferrer"&gt;http://localhost:3000/homemade-gpt-js&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Run these commands from the root of the project. You need to have Node.js ≥ 20.0.0.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js Playground
&lt;/h3&gt;

&lt;p&gt;You may also experiment with the model in Node.js environment.&lt;/p&gt;

&lt;p&gt;Install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch Node.js playground:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run playground-node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/trekhleb/homemade-gpt-js/blob/main/playground-node/src/index.ts" rel="noopener noreferrer"&gt;./playground-node/src/index.ts&lt;/a&gt; file contains the basic example of training and text generation.&lt;/p&gt;

&lt;p&gt;Run these commands from the root of the project. You need to have Node.js ≥ 20.0.0.&lt;/p&gt;




&lt;p&gt;I hope this TS-based GPT example will be helpful for you, learners.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>tensorflow</category>
      <category>javascript</category>
    </item>
    <item>
      <title>System Design Sketches</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Mon, 15 Jul 2024 16:22:35 +0000</pubDate>
      <link>https://dev.to/trekhleb/system-design-sketches-4em0</link>
      <guid>https://dev.to/trekhleb/system-design-sketches-4em0</guid>
      <description>&lt;p&gt;System design sketches for popular system design interview questions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;See the sketches in full resolution at &lt;a href="https://okso.app/showcase/system-design" rel="noopener noreferrer"&gt;okso.app/showcase/system-design&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Social Network
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Functional requirements:
------------------------
- Follow people
- See followers and falowees
- Create posts (text, image, url, @mentions)
- Like posts
- View user feed
- View home feed


Non-functional requirements:
----------------------------
- Add post &amp;lt;500ms
- View feed &amp;lt;500ms
- Post in feed with ~2 mins delay is ok
- Billions of users
- Unlimited followers


Core entities:
--------------
- User
- Follow
- Post


API (RPC-like):
---------------
- POST /getFollowers     {userId}
- POST /getFollowees     {userId}
- POST /followUser       {userId}

- POST /createPost       {text}
- POST /likePost         {postId}

- POST /getHomeFeed      {userId}
- POST /getUserFeed      {userId}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design sketch:&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%2F012tqan9v31i8a2nvmsz.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%2F012tqan9v31i8a2nvmsz.png" alt="Social network" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deep dives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://okso.app/showcase/system-design/page/d0af682e-08cb-4b6f-3e12-1f5c1d3f8aec" rel="noopener noreferrer"&gt;Social network: System design sketch&lt;/a&gt; (okso.app)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.hellointerview.com/learn/system-design/answer-keys/fb-news-feed" rel="noopener noreferrer"&gt;Facebook News Feed&lt;/a&gt; (hellointerview)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=S2y9_XYOZsg" rel="noopener noreferrer"&gt;Instagram + Twitter + Facebook + Reddit&lt;/a&gt; (Jordan has no life)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ride-Sharing App
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Functional requirements:
------------------------
- Rider gets estimated fare (by Start and Destination locations)
- Rider requests a ride based on the estimate
- Driver accepts/denies request + Navigates to pickup/drop-off


Non-functional requirements:
----------------------------
- Low latency for rider-driver matching (&amp;lt;1min)
- Consistency of rider-driver 1:1 matching
  - For one ride, only one driver will get request at a time
- Highly available outside matching
- Handle high-throughput (peak hours, popular events)


Core entities:
--------------
- Rider
- Driver
- Ride
- Location


API:
---------------
- POST /getEstimate({from, to}) --&amp;gt; Partial&amp;lt;Ride&amp;gt;

- POST /requestRide({ride_id}) --&amp;gt; Ride

- POST /getRide({ride_id})

  - gets the latest ride entity to display the
    ride details for both rider and driver apps

- POST /updateLocation({lat, lon})

  - both driver and rider can update their locations
    which may be used to display their on the map
  - drivers might update their location i.e. once
    per 5 seconds (it is needed for matching)
  - however this can be optimised on the client side,
    where we might say that location update is
    proportional to driver speed: for still drivers
    we update location rarely, for moving - more often

- POST /acceptRide({ride_id, accept})
  - ride is being accepted by the driver

- POST /updateRide({ride_id, status})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design sketch:&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%2Fxv2rgemax0a3jw87m3oy.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%2Fxv2rgemax0a3jw87m3oy.png" alt="Ride-sharing app" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deep dives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://okso.app/showcase/system-design/page/3033cade-7fcb-420a-0937-64245b7a1dc4" rel="noopener noreferrer"&gt;Ride-sharing platform: System design sketch&lt;/a&gt; (okso.app)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.hellointerview.com/learn/system-design/answer-keys/uber" rel="noopener noreferrer"&gt;Design Uber&lt;/a&gt; (hellointerview)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Messenger
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Functional requirements:
------------------------
- Group chat (&amp;lt;100 users)
- Send message
- Receive message
- Persist messages (user messages are
  available on multiple devices)


Non-functional requirements:
----------------------------
- Low latency for message delivery (&amp;lt;500ms)
- No lost messages (delivery guarantee)


Core entities:
--------------
- Users
- Groups
- Messages


API:
---------------
- createGroup({users: [], name: ''}) -&amp;gt; {group_id}
- joinGroup({group_id}) -&amp;gt; "ACK"/ "ERR"
- quitGroup({group_id}) -&amp;gt; "ACK"/ "ERR"
- getMyGroups() -&amp;gt; {groups: []}
- getGroupMessages({group_id, max_message_id, min_message_id}) -&amp;gt; {messages: []}

WebSocket:
- connect()
- sendMessage({group_id, message, media: []}) -&amp;gt; "ACK"/ "ERR"
- onGroupUpdated({group_id, participants}) -&amp;gt; "ACK"
- onMessage({chat_id, user_id, message, attachments}) -&amp;gt; "ACK"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design sketch:&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%2Fbszlzsvxhsnbk541ar1w.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%2Fbszlzsvxhsnbk541ar1w.png" alt="Messenger" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deep dives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://okso.app/showcase/system-design/page/4c662fd7-37d4-4864-208c-500f88565839" rel="noopener noreferrer"&gt;Messenger: System design sketch&lt;/a&gt; (okso.app)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=-3Ge8EooS3g" rel="noopener noreferrer"&gt;Facebook Messenger + WhatsApp&lt;/a&gt; (Jordan has no life)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=2Ejdj6QdDD0" rel="noopener noreferrer"&gt;Messenger/WhatsApp Design Deep Dive&lt;/a&gt; (Jordan has no life)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.hellointerview.com/learn/system-design/answer-keys/whatsapp" rel="noopener noreferrer"&gt;Design Whatsapp or Messenger&lt;/a&gt; (hellointerview)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Video Streaming App
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Functional requirements:
------------------------
- Upload video
- Watch video (read-heavy)
- Comment on video


Non-functional requirements:
----------------------------
- Reliable uploads (no corrupted/missing videos)
- Read-heavy (read/write ratio ~100:1)
- Availability &amp;gt; Consistency (1-2 min delay between upload and feed is ok)
- Low latency (before video starts playing)


Core entities:
--------------
- User
- Video Metadata
- Video Chunks
- Users
- Comments


API (RPC-like):
---------------
- POST /initiateUpload  {title, description, video, ...}}
  - server responds with S3 private upload URL
  - the actual video upload is going directly from client to S3

- GET /watch   {video_id}
  - returns video chunks metadata
    - S3 (or CDN) URLs to manifest/playlist files
  - video streaming happens directly from CDNs
  - download by chunks (buffering, ~1Mb), no need to load all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design sketch:&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%2Flwm6ub8gcbcvav67g26v.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%2Flwm6ub8gcbcvav67g26v.png" alt="Video streaming app" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deep dives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://okso.app/showcase/system-design/page/2ef00091-cdfa-4f07-28cf-d0b6e4207de5" rel="noopener noreferrer"&gt;Video streaming platform: System design sketch&lt;/a&gt; (okso.app)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=jPKTo1iGQiE" rel="noopener noreferrer"&gt;Design Youtube&lt;/a&gt; (NeetCode)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=43bB7oSn190" rel="noopener noreferrer"&gt;Netflix + YouTube&lt;/a&gt; (Jordan has no life)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=ghYbFgeqXa0" rel="noopener noreferrer"&gt;System Design: YouTube&lt;/a&gt; (System Design Fight Club)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  File Hosting App
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Functional requirements:
------------------------
- Upload file
- Download file
- Sync files across devices


Non-functional requirements:
----------------------------
- Availability over consistency
  - Download the older version of
    the file instead of waiting
    for a new version to propagate
    is ok
- low latency for uploads and downloads
- support large files (50Gb)
  - resumable uploads
- high data integrity (accurate syncs)


Core entities:
--------------
- File (row bytes)
- File Metadata
- Users


API:
---------------
- POST /uploadFile({metadata}) --&amp;gt; {upload_id, presigned_url}

- POST /getFile({file_id}) --&amp;gt; {file{}, metadata}

- POST /getChanges({since}) --&amp;gt; file_metadata[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design sketch:&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%2Fdhubqhl6a73opxfy5w6e.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%2Fdhubqhl6a73opxfy5w6e.png" alt="File hosting app" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deep dives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://okso.app/showcase/system-design/page/868e746d-0276-40e1-2bcf-b42bceae1b8f" rel="noopener noreferrer"&gt;File hosting app&lt;/a&gt; (okso.app)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.hellointerview.com/learn/system-design/answer-keys/dropbox" rel="noopener noreferrer"&gt;Design Dropbox&lt;/a&gt; (hellointerview)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Web Crawler
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Functional requirements:
------------------------
- Scrape the web starting from seed URLs
- Extract and store text data


Non-functional requirements:
----------------------------
- Fault-tolerant
- Politeness (respect robots.txt, don't DDoS)
- Scale to 1B pages
- Efficient (crawl within a week)


Core entities:
--------------
- URLs
- Text data
- Domain metadata


Interface:
----------
- input: seed URLs
- output: text data


Data Flow:
----------
1. Take seed URLs from a frontier and the IP from DNS
2. Fetch HTML
3. Extract text
4. Store text in the database
5. Extract URLs from the page and add then to the frontier
6. Repeat steps 1-5 until all URLs are crawled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design sketch:&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%2F582a2320wttculaa7w6w.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%2F582a2320wttculaa7w6w.png" alt="Web crawler" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deep dives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://okso.app/showcase/system-design/page/7c557108-277c-4a77-12ce-7622b3493420" rel="noopener noreferrer"&gt;Web-crawler app: System design sketch&lt;/a&gt; (okso.app)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.hellointerview.com/learn/system-design/answer-keys/web-crawler" rel="noopener noreferrer"&gt;Design a Web Crawler&lt;/a&gt; (hellointerview)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=MdWvMX4J-Vc" rel="noopener noreferrer"&gt;Design a Web Crawler&lt;/a&gt; (Jordan has no life)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=BKZxZwUgL3Y" rel="noopener noreferrer"&gt;System Design distributed web crawler&lt;/a&gt; (Tech Dummies Narendra)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>learning</category>
      <category>webdev</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>Micrograd TS</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Mon, 07 Aug 2023 07:50:16 +0000</pubDate>
      <link>https://dev.to/trekhleb/micrograd-ts-32gc</link>
      <guid>https://dev.to/trekhleb/micrograd-ts-32gc</guid>
      <description>&lt;p&gt;I recently went through a very detailed and well-explained Python-based project/lesson by &lt;a href="https://twitter.com/karpathy" rel="noopener noreferrer"&gt;karpathy&lt;/a&gt; which is called &lt;a href="https://github.com/karpathy/micrograd" rel="noopener noreferrer"&gt;micrograd&lt;/a&gt;. This is a tiny scalar-valued autograd engine and a neural net on top of it. &lt;a href="https://www.youtube.com/watch?v=VMj-3S1tku0" rel="noopener noreferrer"&gt;This video&lt;/a&gt; explains how to build such a network from scratch.&lt;/p&gt;

&lt;p&gt;The project above is, as expected, built on &lt;em&gt;Python&lt;/em&gt;. For learning purposes, I wanted to see how such a network may be implemented in &lt;em&gt;TypeScript&lt;/em&gt; and came up with a 🤖 &lt;a href="https://github.com/trekhleb/micrograd-ts" rel="noopener noreferrer"&gt;micrograd-ts&lt;/a&gt; repository (and also with a &lt;a href="https://trekhleb.dev/micrograd-ts/" rel="noopener noreferrer"&gt;demo&lt;/a&gt; of how the network may be trained).&lt;/p&gt;

&lt;p&gt;Trying to build anything on your own very often gives you a much better understanding of a topic. So, this was a good exercise, especially taking into account that the whole code is just a &lt;a href="https://github.com/trekhleb/micrograd-ts/tree/main/micrograd/" rel="noopener noreferrer"&gt;~200 lines&lt;/a&gt; of TS code with no external dependencies.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/trekhleb/micrograd-ts" rel="noopener noreferrer"&gt;micrograd-ts&lt;/a&gt; repository might be useful for those who want to get a basic understanding of how neural networks work, using a TypeScript environment for experimentation.&lt;/p&gt;

&lt;p&gt;With that being said, let me give you some more information about the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project structure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/micrograd-ts/tree/main/micrograd/" rel="noopener noreferrer"&gt;micrograd/&lt;/a&gt; — this folder is the core/purpose of the repo

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/micrograd-ts/tree/main/micrograd/engine.ts" rel="noopener noreferrer"&gt;engine.ts&lt;/a&gt; — the scalar &lt;code&gt;Value&lt;/code&gt; class that supports basic math operations like &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;sub&lt;/code&gt;, &lt;code&gt;div&lt;/code&gt;, &lt;code&gt;mul&lt;/code&gt;, &lt;code&gt;pow&lt;/code&gt;, &lt;code&gt;exp&lt;/code&gt;, &lt;code&gt;tanh&lt;/code&gt; and has a &lt;code&gt;backward()&lt;/code&gt; method that calculates a derivative of the expression, which is required for back-propagation flow.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/micrograd-ts/tree/main/micrograd/nn.ts" rel="noopener noreferrer"&gt;nn.ts&lt;/a&gt; — the &lt;code&gt;Neuron&lt;/code&gt;, &lt;code&gt;Layer&lt;/code&gt;, and &lt;code&gt;MLP&lt;/code&gt; (multi-layer perceptron) classes that implement a neural network on top of the differentiable scalar &lt;code&gt;Values&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/trekhleb/micrograd-ts/tree/main/demo/" rel="noopener noreferrer"&gt;demo/&lt;/a&gt; - demo React application to experiment with the micrograd code

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/trekhleb/micrograd-ts/tree/main/demo/src/demos/" rel="noopener noreferrer"&gt;src/demos/&lt;/a&gt; - several playgrounds where you can experiment with the &lt;code&gt;Neuron&lt;/code&gt;, &lt;code&gt;Layer&lt;/code&gt;, and &lt;code&gt;MLP&lt;/code&gt; classes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Micrograd
&lt;/h2&gt;

&lt;p&gt;See the 🎬 &lt;a href="https://www.youtube.com/watch?v=VMj-3S1tku0" rel="noopener noreferrer"&gt;The spelled-out intro to neural networks and back-propagation: building micrograd&lt;/a&gt; YouTube video for the detailed explanation of how neural networks and backpropagation work. The video also explains in detail what the &lt;code&gt;Neuron&lt;/code&gt;, &lt;code&gt;Layer&lt;/code&gt;, &lt;code&gt;MLP&lt;/code&gt;, and &lt;code&gt;Value&lt;/code&gt; classes do.&lt;/p&gt;

&lt;p&gt;Briefly, the &lt;code&gt;Value&lt;/code&gt; class allows you to build a computation graph for some expression that consists of scalar values.&lt;/p&gt;

&lt;p&gt;Here is an example of how the computation graph for the &lt;code&gt;a * b + c&lt;/code&gt; expression looks like:&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%2Fetpgggcij09iui7yk59n.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%2Fetpgggcij09iui7yk59n.png" alt=" " width="800" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the &lt;code&gt;Value&lt;/code&gt; class we can build a &lt;code&gt;Neuron&lt;/code&gt; expression &lt;code&gt;X * W + b&lt;/code&gt;. Here we're simulating a dot-product of matrix &lt;code&gt;X&lt;/code&gt; (input features) and matrix &lt;code&gt;W&lt;/code&gt; (neuron weights):&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%2Fs4kol7qmsaq7ki447oh7.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%2Fs4kol7qmsaq7ki447oh7.png" alt=" " width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Out of &lt;code&gt;Neurons&lt;/code&gt;, we can build the &lt;code&gt;MLP&lt;/code&gt; network class that consists of several &lt;code&gt;Layers&lt;/code&gt; of &lt;code&gt;Neurons&lt;/code&gt;. The computation graph in this case may look a bit complex to be displayed here, but a simplified version might look like this:&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%2F46z90bfvxbvpmvbg5fa0.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%2F46z90bfvxbvpmvbg5fa0.png" alt=" " width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main idea is that the computation graphs above "know" how to do automatic back propagation (in other words, how to calculate derivatives). This allows us to train the MLP network for several epochs and adjust the network weights in a way that reduces the ultimate loss:&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%2Fk7ed4u5clyyt4jan5957.gif" 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%2Fk7ed4u5clyyt4jan5957.gif" alt=" " width="960" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo (online)
&lt;/h2&gt;

&lt;p&gt;To see the online demo/playground, check the following link:&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://trekhleb.dev/micrograd-ts" rel="noopener noreferrer"&gt;trekhleb.dev/micrograd-ts&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo (local)
&lt;/h2&gt;

&lt;p&gt;If you want to experiment with the code locally, follow the instructions below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Clone the current repo locally.&lt;/p&gt;

&lt;p&gt;Switch to the demo folder:&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="nb"&gt;cd&lt;/span&gt; ./demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setup node v18 using &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;nvm&lt;/a&gt; (optional):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm use
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch demo app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The demo app will be available at &lt;code&gt;http://localhost:5173/micrograd-ts&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Playgrounds
&lt;/h3&gt;

&lt;p&gt;Go to the &lt;a href="https://github.com/trekhleb/micrograd-ts/tree/main/demo/src/demos/" rel="noopener noreferrer"&gt;./demo/src/demos/&lt;/a&gt; to explore several playgrounds for the &lt;code&gt;Neuron&lt;/code&gt;, &lt;code&gt;Layer&lt;/code&gt;, and &lt;code&gt;MLP&lt;/code&gt; classes.&lt;/p&gt;




&lt;p&gt;I hope, playing around with the micrograd-ts code above and watching the video from Karpathy will be helpful at least for some of you, learners.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Oan0VOWUBYo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Observations</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Tue, 27 Jun 2023 19:30:36 +0000</pubDate>
      <link>https://dev.to/trekhleb/observations-4ee</link>
      <guid>https://dev.to/trekhleb/observations-4ee</guid>
      <description>&lt;p&gt;This is a collection of my subjective assumptions, questions, and interpretations about the world around us. Don’t take it seriously.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Check the &lt;a href="https://trekhleb.dev/blog/2023/observations/" rel="noopener noreferrer"&gt;Observations&lt;/a&gt; post for the detailed breakdown of observations and assumptions that has interactive dependency graph&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&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%2Foidd0xgb48eaavkj1wqx.gif" 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%2Foidd0xgb48eaavkj1wqx.gif" alt="Observations dependency graph" width="720" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[WB3] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-wb3" rel="noopener noreferrer"&gt;We are like &lt;strong&gt;2D&lt;/strong&gt; people trying to grasp the &lt;strong&gt;3D&lt;/strong&gt; ideas&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[BZ4] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-bz4" rel="noopener noreferrer"&gt;We are like a &lt;strong&gt;fetus&lt;/strong&gt; in a mother’s belly trying to think about &lt;strong&gt;life after&lt;/strong&gt; birth&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[BS3] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-bs3" rel="noopener noreferrer"&gt;Every physical object that we can grasp has an &lt;strong&gt;origin&lt;/strong&gt; or a &lt;strong&gt;cause&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[XGT] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-xgt" rel="noopener noreferrer"&gt;Science doesn’t have an answer to the question of &lt;strong&gt;ultimate origin&lt;/strong&gt; for now&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[HT9] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-ht9" rel="noopener noreferrer"&gt;In science, some &lt;strong&gt;theories&lt;/strong&gt; are getting &lt;strong&gt;reconsidered&lt;/strong&gt; over time&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[HX2] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-hx2" rel="noopener noreferrer"&gt;In science, some &lt;strong&gt;theories&lt;/strong&gt; are not &lt;strong&gt;accepted&lt;/strong&gt; at first&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[ML1] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-ml1" rel="noopener noreferrer"&gt;There is a &lt;strong&gt;non-zero&lt;/strong&gt; chance that a scientific theory will be &lt;strong&gt;reconsidered&lt;/strong&gt; or &lt;strong&gt;rejected&lt;/strong&gt; in the future&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[VG2] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-vg2" rel="noopener noreferrer"&gt;Science operates with &lt;strong&gt;axioms&lt;/strong&gt; that need to be &lt;strong&gt;believed&lt;/strong&gt; in&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[ME3] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-me3" rel="noopener noreferrer"&gt;Every mathematical system relies on at least one &lt;strong&gt;true&lt;/strong&gt; statement that &lt;strong&gt;cannot&lt;/strong&gt; be proven&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[CW5] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-cw5" rel="noopener noreferrer"&gt;To answer the question of &lt;strong&gt;origin&lt;/strong&gt; we need an axiom or a statement of the &lt;strong&gt;Creator / Initiator / Designer / God&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[HT4] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-ht4" rel="noopener noreferrer"&gt;&lt;strong&gt;Spiritual&lt;/strong&gt; and &lt;strong&gt;scientific&lt;/strong&gt; paths are not contradictory, but &lt;strong&gt;convergent&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[SQ4] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-sq4" rel="noopener noreferrer"&gt;&lt;strong&gt;Scientists’&lt;/strong&gt; quotes about the &lt;strong&gt;Creator&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[PW8] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-pw8" rel="noopener noreferrer"&gt;The &lt;strong&gt;Creator&lt;/strong&gt; is more advanced than the &lt;strong&gt;Creature&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[TG9] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-tg9" rel="noopener noreferrer"&gt;A child can be born only from &lt;strong&gt;father&lt;/strong&gt; and &lt;strong&gt;mother&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[BQ2] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-bq2" rel="noopener noreferrer"&gt;The &lt;strong&gt;Creator&lt;/strong&gt; has &lt;strong&gt;consciousness&lt;/strong&gt; and &lt;strong&gt;feelings&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[NW7] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-nw7" rel="noopener noreferrer"&gt;You and your physical traits are &lt;strong&gt;unique&lt;/strong&gt; throughout the history of Earth&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[EA5] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-ea5" rel="noopener noreferrer"&gt;The &lt;strong&gt;Universe&lt;/strong&gt; is &lt;strong&gt;fine-tuned&lt;/strong&gt; for your existence&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[PU9] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-pu9" rel="noopener noreferrer"&gt;You are &lt;strong&gt;unique&lt;/strong&gt; and you have a &lt;strong&gt;purpose&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[UR9] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-ur9" rel="noopener noreferrer"&gt;In most movies &lt;strong&gt;good&lt;/strong&gt; defeats &lt;strong&gt;evil&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[HB5] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-hb5" rel="noopener noreferrer"&gt;Human beings have an embedded &lt;strong&gt;good-vs-evil “sensor”&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[GS1] &lt;a href="https://trekhleb.dev/blog/2023/observations/#observation-gs1" rel="noopener noreferrer"&gt;Human beings sense &lt;strong&gt;non-physical dimensions&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[GS2] &lt;a href="https://trekhleb.dev/blog/2023/observations/#assumption-gs2" rel="noopener noreferrer"&gt;Human beings have embedded &lt;strong&gt;God’s sensor&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>learning</category>
    </item>
    <item>
      <title>SOLID Principles Sketches</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Wed, 05 Oct 2022 00:45:15 +0000</pubDate>
      <link>https://dev.to/trekhleb/solid-principles-sketches-486p</link>
      <guid>https://dev.to/trekhleb/solid-principles-sketches-486p</guid>
      <description>&lt;p&gt;I've recently launched the minimalistic drawing app &lt;a href="https://okso.app/" rel="noopener noreferrer"&gt;okso.app&lt;/a&gt; that allows you to do interactive (nested) sketches. And, as a continuation of my previous &lt;a href="https://dev.to/trekhleb/s-o-l-i-d-principles-around-you-1o17"&gt;S.O.L.I.D. Principles Around You&lt;/a&gt; article, I've organised it in &lt;a href="https://okso.app/showcase/solid" rel="noopener noreferrer"&gt;interactive sketches&lt;/a&gt; that you may find &lt;a href="https://okso.app/showcase/solid" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check what I've got:&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%2Fikhn9kdz1n48vuhn9d7s.gif" 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%2Fikhn9kdz1n48vuhn9d7s.gif" alt=" " width="720" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, each SOLID principle has a dedicated sketch page that look like the following&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%2F9pkgrl0dfal37s5ui7gc.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%2F9pkgrl0dfal37s5ui7gc.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Single Responsibility Principle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://okso.app/showcase/solid/page/924000bf-21ec-4580-36f4-49ee920abe55" rel="noopener noreferrer"&gt;SRP Sketch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A class should have only a single responsibility. Only one potential change in the software’s specification should be able to affect the specification of the class.&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%2Fpotejokx5xk0de88jmup.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%2Fpotejokx5xk0de88jmup.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Open/Closed Principle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://okso.app/showcase/solid/page/f297d650-5343-4423-39b9-6a1dbb21e5df" rel="noopener noreferrer"&gt;OCP Sketch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Software entities should be open for EXTENSION, but closed for MODIFICATION. Allow behavior to be extended without modifying the source code.&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%2F0u89uxzdevl0f6dig0v4.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%2F0u89uxzdevl0f6dig0v4.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Liskov Substitution Principle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://okso.app/showcase/solid/page/2899b427-2bd8-4899-16a7-0ce855331ba2" rel="noopener noreferrer"&gt;LSP Sketch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.&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%2Fskmtp2hpn2x8jlh1pt51.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%2Fskmtp2hpn2x8jlh1pt51.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Interface Segregation Principle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://okso.app/showcase/solid/page/5464baff-5793-482a-0dfa-bab4337fe3ed" rel="noopener noreferrer"&gt;ISP Sketch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many client-specific interfaces are better than one general-purpose interface. No client should be forced to depend on methods it does not use.&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%2Fm093jpxjr3oksfyncqlj.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%2Fm093jpxjr3oksfyncqlj.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Inversion Principle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://okso.app/showcase/solid/page/70a27e39-47db-4ada-2065-f023372e1933" rel="noopener noreferrer"&gt;DIP Sketch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One should depend upon abstractions, not concretions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High-level modules should not depend on low-level modules. Both should depend on abstractions.&lt;/li&gt;
&lt;li&gt;Abstractions should not depend on details. Details should depend on abstractions.&lt;/li&gt;
&lt;/ul&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%2Faanqz5a2jna0v8oorxam.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%2Faanqz5a2jna0v8oorxam.png" alt=" " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the future I plan to add more visual explainers like this one to the &lt;a href="https://okso.app/showcase" rel="noopener noreferrer"&gt;okso.app showcase&lt;/a&gt;. Currently there is a &lt;a href="https://okso.app/showcase/data-structures" rel="noopener noreferrer"&gt;Data Structures&lt;/a&gt; sketch is available that is done in a similar style as SOLID one. I hope having such visual explainers in one place will be convenient for you.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Data Structure Sketches</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Wed, 31 Aug 2022 10:31:39 +0000</pubDate>
      <link>https://dev.to/trekhleb/data-structure-sketches-39i1</link>
      <guid>https://dev.to/trekhleb/data-structure-sketches-39i1</guid>
      <description>&lt;p&gt;Recently I launched the minimalistic online drawing app &lt;a href="https://okso.app" rel="noopener noreferrer"&gt;okso.app&lt;/a&gt;. I wanted it to be a place where people could do fast, ad-hoc, napkin-based-like explanations of any concept as if you are sitting with your friend and trying to explain him/her something during lunch. Don't ask me why it is needed, I was just experimenting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Btw, that's why the app name is "Ok! So...", because oftentimes these are the opening words after you pick up the pen and the piece of paper (or a whiteboard) and start drawing. I didn't see the study and the statistics of the opening phrases though, so I might be wrong here, here 😀&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, the first concept I've tried to explain with sketches was the Data Structures. Without further ado, here is the interactive ✍🏻 &lt;a href="https://okso.app/showcase/data-structures" rel="noopener noreferrer"&gt;Data Structure Sketches&lt;/a&gt; showcase that you may play with.&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%2Fxmzi8rind4s293f8axdb.gif" 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%2Fxmzi8rind4s293f8axdb.gif" alt="Data Structure Sketches" width="720" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a YouTube version of the GIF just in case:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/yaOWTOWOWGk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Of course, not all data structures are covered. And of course, this is not comprehensive material, but rather a cheatsheet that would create visual hints and associations for the following data structures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linked List&lt;/li&gt;
&lt;li&gt;Doubly Linked List&lt;/li&gt;
&lt;li&gt;Queue&lt;/li&gt;
&lt;li&gt;Stack&lt;/li&gt;
&lt;li&gt;Hash Table (with hash collision resolution)&lt;/li&gt;
&lt;li&gt;Tree (including the Binary Search Tree)&lt;/li&gt;
&lt;li&gt;Heap (including Mean Heap and Max Heap)&lt;/li&gt;
&lt;li&gt;Trie&lt;/li&gt;
&lt;li&gt;Graph&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each box on the sketch is clickable, so you may dig into the data structure you're interested. For example &lt;code&gt;Heap → Max Heap&lt;/code&gt;, or &lt;code&gt;Heap → Min Heap&lt;/code&gt;, or &lt;code&gt;Heap → Array Representation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The sketches are split into so-called Pages just to make it easier to grasp them, so the users stay focused on one concept at a time, they see the relationship between the concept, and thus, hopefully, they are not getting overwhelmed with seeing a lot of information at the same time on one drawing/page.&lt;/p&gt;

&lt;p&gt;Each page has a link to the source-code examples that are implementing the data structure on JavaScript.&lt;/p&gt;

&lt;p&gt;Here are some examples of the sketches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Doubly Linked List&lt;/strong&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%2Fuploads%2Farticles%2F1mly45gac8oz3qhxvbyg.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%2F1mly45gac8oz3qhxvbyg.png" alt="Doubly Linked List" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tree&lt;/strong&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%2Fuploads%2Farticles%2Fp4kugg8t2u8h8mm6o6ht.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%2Fp4kugg8t2u8h8mm6o6ht.png" alt="Doubly Linked List" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hash Table&lt;/strong&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%2Fuploads%2Farticles%2Fvi97kgfagg30p9meeka9.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%2Fvi97kgfagg30p9meeka9.png" alt="Doubly Linked List" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trie&lt;/strong&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%2Fuploads%2Farticles%2Fh4s4w8wey4p4o67utldm.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%2Fh4s4w8wey4p4o67utldm.png" alt="Doubly Linked List" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Graph&lt;/strong&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%2Fuploads%2Farticles%2F4e5rsrias5omal53os0y.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%2F4e5rsrias5omal53os0y.png" alt="Doubly Linked List" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full list you may find in the ✍🏻 &lt;a href="https://okso.app/showcase/data-structures" rel="noopener noreferrer"&gt;Data Structure Sketches&lt;/a&gt; showcase.&lt;/p&gt;

&lt;p&gt;I hope you find this showcase useful and I hope it will be a good visual cheatsheet-like complement to your data structure knowledge.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Ok! So... The drawing app to express, grasp, and organize your thoughts and ideas</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Wed, 20 Jul 2022 15:21:37 +0000</pubDate>
      <link>https://dev.to/trekhleb/ok-so-the-drawing-app-to-express-grasp-and-organize-your-thoughts-and-ideas-3pij</link>
      <guid>https://dev.to/trekhleb/ok-so-the-drawing-app-to-express-grasp-and-organize-your-thoughts-and-ideas-3pij</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;a href="https://okso.app" rel="noopener noreferrer"&gt;OkSo&lt;/a&gt; app is the drawing app to express, grasp, and organize your thoughts and ideas. Draw to explain. Draw to grasp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Concept
&lt;/h2&gt;

&lt;p&gt;Some of you are visual learners. You need to see pictures and visualizations &lt;strong&gt;to explain&lt;/strong&gt; and &lt;strong&gt;grasp&lt;/strong&gt; concepts. You keep a &lt;strong&gt;pencil&lt;/strong&gt; and a &lt;strong&gt;piece of paper&lt;/strong&gt; at hand. Sometimes it feels like connecting two circles with an arrow would speak more apparent than describing such circles' relationship with words. Visualizations, drawings, and sketches help you organize your thoughts and knowledge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F1leu921e1e7oi0qtruc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F1leu921e1e7oi0qtruc3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The process of visualization is not always easy. It requires some thinking and energy. That's why you might find yourself taking a deep breath, and saying &lt;em&gt;"Ok! So..."&lt;/em&gt; to yourself or your vis-à-vis before diving deep into the concept. That's the reason for &lt;strong&gt;the Thinker&lt;/strong&gt; with the &lt;strong&gt;"Ok! So..."&lt;/strong&gt; in the logo.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;physical paper&lt;/strong&gt; or the notepad is good but it has its limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You may forget it at home.&lt;/li&gt;
&lt;li&gt;The page space might not be enough to contain all the details.&lt;/li&gt;
&lt;li&gt;Often you only have pens of one or two colors.&lt;/li&gt;
&lt;li&gt;If you made a typo you can't just undo/redo it, the sketch is not really editable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;OkSo&lt;/strong&gt; app tries to overcome these limitations and gives users the possibility to "Draw to explain" and "Draw to grasp".&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;The limitations mentioned above are being addressed as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://okso.app" rel="noopener noreferrer"&gt;OkSo&lt;/a&gt; app is available online and thus it is always with you. &lt;em&gt;Currently, you may export all your drawings to the file and share them between devices manually (i.e. via Google Docs or Dropbox). All your drawings are stored in your browser. We don't send your data to the back-end. The possibility to automatically sync your drawings between devices is in our &lt;a href="https://feedback.okso.app/" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt;.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;It gives you an "infinite" canvas.&lt;/li&gt;
&lt;li&gt;No color limits.&lt;/li&gt;
&lt;li&gt;You may edit your drawings and undo/redo your edits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fpi7s3z8inrax2eentssi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fpi7s3z8inrax2eentssi.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many online drawing apps give you these (and not only) possibilities. Take a look at &lt;a href="https://www.tldraw.com/" rel="noopener noreferrer"&gt;tldraw&lt;/a&gt; or &lt;a href="https://excalidraw.com/" rel="noopener noreferrer"&gt;excalidraw&lt;/a&gt;, for example. These apps are awesome! Even more, the &lt;a href="https://okso.pp" rel="noopener noreferrer"&gt;OkSo&lt;/a&gt; app is built on top of the &lt;a href="https://www.npmjs.com/package/@tldraw/tldraw" rel="noopener noreferrer"&gt;@tldraw/tldraw&lt;/a&gt; NPM package itself.&lt;/p&gt;

&lt;p&gt;However, what the OkSo app tries to do on top of that is to experiment with the way you &lt;strong&gt;organize your drawings&lt;/strong&gt;. It uses the concept of &lt;strong&gt;nested pages&lt;/strong&gt;. The page (to be more precise the link to a page) is a first-class citizen of your drawing along with other shapes like freehand curves, rectangles, ellipses, or texts. So you may embed/draw &lt;em&gt;links to sub-pages inside the page&lt;/em&gt;. It means that you may organize your drawings in the nested tree structure.&lt;/p&gt;

&lt;p&gt;For example, here is one of the variants you may organize your drawings/pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Root drawing
  ├─ Goals
  │     ├─ 2021
  │     ├─ 2022
  │     └─ ...
  ├─ Career
  └─ Learning
        ├─ Machine Learning
        └─ Algorithms breakdown
              ├─ Binary search
              ├─ Power Set
              └─ ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each item in this tree is a separate drawing/page itself. The &lt;strong&gt;content&lt;/strong&gt; of each page might be anything you are using your notepad for. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;My 2022 goals&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;My career plans&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The "Drawing App" system design&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Binary search algorithm breakdown&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Brainstorming the startup ideas&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The AI learning path&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Logistics for my next trip&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;You name it...&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fact that the link to the sub-page is just a regular shape allows you to use &lt;strong&gt;size- and color-coding&lt;/strong&gt;, to group the links together, and to easily distinguish them visually.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fq2cv9558x8dvz6o2w6ho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fq2cv9558x8dvz6o2w6ho.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, compared to the flat lists, &lt;strong&gt;you'll not be overwhelmed by a large number of pages&lt;/strong&gt;, since they may be organized in a tree structure. You will only see the links to the sub-pages of a particular level. You can "travel" easily between the sub-pages back and forth, deeper and deeper until you find a page you need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F20z6hzgxvu1so9bqmj3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F20z6hzgxvu1so9bqmj3u.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another approach, that the OkSo app takes compared to the other drawing apps is to be &lt;strong&gt;as simple and as minimalist as possible&lt;/strong&gt; (just like your physical notepad). This relates not only to the UI but to the list of tools and features in particular (therefore the rectangle, the ellipse, and the arrow are hidden from the tools panel by default). For example, instead of having a reach collection of primitives, what about just drawing the "DataBase Cylinder" icon from scratch? Yes, one of the real reasons for that is plain simple laziness and desire to code less :D However, I believe, this approach also feels more authentic and artistic. When you use a whiteboard during the technical interview or during the brainstorming you draw such primitives easily, aren't you? Plus, having such basic functionalities as copy-pasting, cloning, and resizing should allow you to deliver your thought fast and easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fr65loh91kj9x2dpg18ex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fr65loh91kj9x2dpg18ex.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The OkSo app is a &lt;strong&gt;Progressive Web App&lt;/strong&gt; (PWA). It means that you may install it on your device (add to your home screen) for faster access (see &lt;a href="https://support.google.com/chrome/answer/9658361?hl=en&amp;amp;co=GENIE.Platform%3DDesktop&amp;amp;oco=1" rel="noopener noreferrer"&gt;instructions&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Here is a demo of how the okso.app may be used to explain/grasp the idea behind some basic data structures:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/2833pSyP2k0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;Note, that the app is in its &lt;strong&gt;early beta stage&lt;/strong&gt; and some features from our &lt;a href="https://feedback.okso.app/" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt; are still in progress and will be delivered soon.&lt;/p&gt;

&lt;p&gt;Meanwhile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;feel free to &lt;a href="https://okso.app/subscribe" rel="noopener noreferrer"&gt;subscribe to the product updates&lt;/a&gt; if you're interested&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://feedback.okso.app/feedback" rel="noopener noreferrer"&gt;leave feedback&lt;/a&gt; (i.e. suggest a feature or report a bug)&lt;/li&gt;
&lt;li&gt;and &lt;a href="https://twitter.com/okso_app" rel="noopener noreferrer"&gt;follow OkSo on Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>productivity</category>
      <category>news</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Top 33 JavaScript Projects on GitHub (November 2021)</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Sat, 13 Nov 2021 15:23:08 +0000</pubDate>
      <link>https://dev.to/trekhleb/top-33-javascript-projects-on-github-november-2021-41d4</link>
      <guid>https://dev.to/trekhleb/top-33-javascript-projects-on-github-november-2021-41d4</guid>
      <description>&lt;p&gt;2021 is coming to its end, and we may do another snapshot of &lt;strong&gt;33 most starred open-sourced JavaScript repositories&lt;/strong&gt; on GitHub &lt;strong&gt;as of November 13th, 2021&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Previous snapshots: &lt;a href="https://trekhleb.dev/blog/2018/top-33-javascript-projects-on-github-august-2018/" rel="noopener noreferrer"&gt;2018&lt;/a&gt;, &lt;a href="https://trekhleb.dev/blog/2020/top-33-javascript-projects-on-github-december/" rel="noopener noreferrer"&gt;2020&lt;/a&gt;, &lt;a href="http://localhost:8000/blog/2021/top-33-javascript-projects-on-github/" rel="noopener noreferrer"&gt;2021&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You may also &lt;a href="https://github.com/search?l=&amp;amp;o=desc&amp;amp;q=stars%3A%3E1+language%3AJavaScript&amp;amp;s=stars&amp;amp;type=Repositories" rel="noopener noreferrer"&gt;query the GitHub&lt;/a&gt; to fetch the latest results.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  #1 &lt;a href="https://github.com/freeCodeCamp/freeCodeCamp" rel="noopener noreferrer"&gt;freeCodeCamp/freeCodeCamp&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;freeCodeCamp.org's open-source codebase and curriculum. Learn to code for free.&lt;br&gt;
&lt;em&gt;★ 335k&lt;/em&gt; &lt;em&gt;(+18k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #2 &lt;a href="https://github.com/vuejs/vue" rel="noopener noreferrer"&gt;vuejs/vue&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.&lt;br&gt;
&lt;em&gt;★ 190k&lt;/em&gt; &lt;em&gt;(+14k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #3 &lt;a href="https://github.com/facebook/react" rel="noopener noreferrer"&gt;facebook/react&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A declarative, efficient, and flexible JavaScript library for building user interfaces.&lt;br&gt;
&lt;em&gt;★ 177k&lt;/em&gt; &lt;em&gt;(+17k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #4 &lt;a href="https://github.com/twbs/bootstrap" rel="noopener noreferrer"&gt;twbs/bootstrap&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.&lt;br&gt;
&lt;em&gt;★ 154k&lt;/em&gt; &lt;em&gt;(+8k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #5 &lt;a href="https://github.com/trekhleb/javascript-algorithms" rel="noopener noreferrer"&gt;trekhleb/javascript-algorithms&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Algorithms and data structures implemented in JavaScript with explanations and links to further readings&lt;br&gt;
&lt;em&gt;★ 126k&lt;/em&gt; &lt;em&gt;(+37k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #6 &lt;a href="https://github.com/airbnb/javascript" rel="noopener noreferrer"&gt;airbnb/javascript&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;JavaScript Style Guide&lt;br&gt;
&lt;em&gt;★ 116k&lt;/em&gt; &lt;em&gt;(+13k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #7 &lt;a href="https://github.com/facebook/react-native" rel="noopener noreferrer"&gt;facebook/react-native&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A framework for building native applications using React&lt;br&gt;
&lt;em&gt;★ 99k&lt;/em&gt; &lt;em&gt;(+7k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #8 &lt;a href="https://github.com/d3/d3" rel="noopener noreferrer"&gt;d3/d3&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Bring data to life with SVG, Canvas and HTML.&lt;br&gt;
&lt;em&gt;★ 99k&lt;/em&gt; &lt;em&gt;(+4k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #9 &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;facebook/create-react-app&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Set up a modern web app by running one command.&lt;br&gt;
&lt;em&gt;★ 91k&lt;/em&gt; &lt;em&gt;(+7k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #10 &lt;a href="https://github.com/axios/axios" rel="noopener noreferrer"&gt;axios/axios&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Promise based HTTP client for the browser and node.js&lt;br&gt;
&lt;em&gt;★ 89k&lt;/em&gt; &lt;em&gt;(+9k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #11 &lt;a href="https://github.com/30-seconds/30-seconds-of-code" rel="noopener noreferrer"&gt;30-seconds/30-seconds-of-code&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Short JavaScript code snippets for all your development needs&lt;br&gt;
&lt;em&gt;★ 88k&lt;/em&gt; &lt;em&gt;(+22k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #12 &lt;a href="https://github.com/nodejs/node" rel="noopener noreferrer"&gt;nodejs/node&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Node.js JavaScript runtime&lt;br&gt;
&lt;em&gt;★ 83k&lt;/em&gt; &lt;em&gt;(+7k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #13 &lt;a href="https://github.com/vercel/next.js" rel="noopener noreferrer"&gt;vercel/next.js&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The React Framework&lt;br&gt;
&lt;em&gt;★ 76k&lt;/em&gt; &lt;em&gt;(+18k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #14 &lt;a href="https://github.com/mrdoob/three.js" rel="noopener noreferrer"&gt;mrdoob/three.js&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;JavaScript 3D Library.&lt;br&gt;
&lt;em&gt;★ 75k&lt;/em&gt; &lt;em&gt;(+10k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #15 &lt;a href="https://github.com/mui-org/material-ui" rel="noopener noreferrer"&gt;mui-org/material-ui&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;MUI (formerly Material-UI) is the React UI library you always wanted. Follow your own design system, or start with Material Design.&lt;br&gt;
&lt;em&gt;★ 72k&lt;/em&gt; &lt;em&gt;(+9k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #16 &lt;a href="https://github.com/goldbergyoni/nodebestpractices" rel="noopener noreferrer"&gt;goldbergyoni/nodebestpractices&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The Node.js best practices list (October 2021)&lt;br&gt;
&lt;em&gt;★ 72k&lt;/em&gt; &lt;em&gt;(+15k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #17 &lt;a href="https://github.com/awesome-selfhosted/awesome-selfhosted" rel="noopener noreferrer"&gt;awesome-selfhosted/awesome-selfhosted&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A list of Free Software network services and web applications which can be hosted on your own servers&lt;br&gt;
&lt;em&gt;★ 67k&lt;/em&gt; &lt;em&gt;(+16k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #18 &lt;a href="https://github.com/FortAwesome/Font-Awesome" rel="noopener noreferrer"&gt;FortAwesome/Font-Awesome&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The iconic SVG, font, and CSS toolkit&lt;br&gt;
&lt;em&gt;★ 66k&lt;/em&gt; &lt;em&gt;(+1k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #19 &lt;a href="https://github.com/yangshun/tech-interview-handbook" rel="noopener noreferrer"&gt;yangshun/tech-interview-handbook&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Curated interview preparation materials for busy engineers&lt;br&gt;
&lt;em&gt;★ 60k&lt;/em&gt; &lt;em&gt;(+60k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #20 &lt;a href="https://github.com/ryanmcdermott/clean-code-javascript" rel="noopener noreferrer"&gt;ryanmcdermott/clean-code-javascript&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Clean Code concepts adapted for JavaScript&lt;br&gt;
&lt;em&gt;★ 59k&lt;/em&gt; &lt;em&gt;(+59k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #21 &lt;a href="https://github.com/webpack/webpack" rel="noopener noreferrer"&gt;webpack/webpack&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.&lt;br&gt;
&lt;em&gt;★ 59k&lt;/em&gt; &lt;em&gt;(+3k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #22 &lt;a href="https://github.com/angular/angular.js" rel="noopener noreferrer"&gt;angular/angular.js&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;AngularJS - HTML enhanced for web apps!&lt;br&gt;
&lt;em&gt;★ 59k&lt;/em&gt; &lt;em&gt;(+0k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #23 &lt;a href="https://github.com/hakimel/reveal.js" rel="noopener noreferrer"&gt;hakimel/reveal.js&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The HTML Presentation Framework&lt;br&gt;
&lt;em&gt;★ 57k&lt;/em&gt; &lt;em&gt;(+2k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #24 &lt;a href="https://github.com/typicode/json-server" rel="noopener noreferrer"&gt;typicode/json-server&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Get a full fake REST API with zero coding in less than 30 seconds (seriously)&lt;br&gt;
&lt;em&gt;★ 57k&lt;/em&gt; &lt;em&gt;(+6k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #25 &lt;a href="https://github.com/atom/atom" rel="noopener noreferrer"&gt;atom/atom&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The hackable text editor&lt;br&gt;
&lt;em&gt;★ 56k&lt;/em&gt; &lt;em&gt;(+2k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #26 &lt;a href="https://github.com/jquery/jquery" rel="noopener noreferrer"&gt;jquery/jquery&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;jQuery JavaScript Library&lt;br&gt;
&lt;em&gt;★ 55k&lt;/em&gt; &lt;em&gt;(+1k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #27 &lt;a href="https://github.com/chartjs/Chart.js" rel="noopener noreferrer"&gt;chartjs/Chart.js&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Simple HTML5 Charts using the canvas tag&lt;br&gt;
&lt;em&gt;★ 55k&lt;/em&gt; &lt;em&gt;(+4k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #28 &lt;a href="https://github.com/expressjs/express" rel="noopener noreferrer"&gt;expressjs/express&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Fast, unopinionated, minimalist web framework for node.&lt;br&gt;
&lt;em&gt;★ 54k&lt;/em&gt; &lt;em&gt;(+3k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #29 &lt;a href="https://github.com/adam-p/markdown-here" rel="noopener noreferrer"&gt;adam-p/markdown-here&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Google Chrome, Firefox, and Thunderbird extension that lets you write email in Markdown and render it before sending.&lt;br&gt;
&lt;em&gt;★ 53k&lt;/em&gt; &lt;em&gt;(+4k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #30 &lt;a href="https://github.com/h5bp/html5-boilerplate" rel="noopener noreferrer"&gt;h5bp/html5-boilerplate&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A professional front-end template for building fast, robust, and adaptable web apps or sites.&lt;br&gt;
&lt;em&gt;★ 51k&lt;/em&gt; &lt;em&gt;(+51k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #31 &lt;a href="https://github.com/gatsbyjs/gatsby" rel="noopener noreferrer"&gt;gatsbyjs/gatsby&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Build blazing fast, modern apps and websites with React&lt;br&gt;
&lt;em&gt;★ 51k&lt;/em&gt; &lt;em&gt;(+3k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #32 &lt;a href="https://github.com/lodash/lodash" rel="noopener noreferrer"&gt;lodash/lodash&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A modern JavaScript utility library delivering modularity, performance, and extras.&lt;br&gt;
&lt;em&gt;★ 51k&lt;/em&gt; &lt;em&gt;(+3k)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #33 &lt;a href="https://github.com/resume/resume.github.com" rel="noopener noreferrer"&gt;resume/resume.github.com&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Resumes generated using the GitHub informations&lt;br&gt;
&lt;em&gt;★ 50k&lt;/em&gt; &lt;em&gt;(+3k)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>Weighted Random algorithm in JavaScript</title>
      <dc:creator>Oleksii Trekhleb</dc:creator>
      <pubDate>Fri, 22 Oct 2021 12:19:47 +0000</pubDate>
      <link>https://dev.to/trekhleb/weighted-random-algorithm-in-javascript-1pdc</link>
      <guid>https://dev.to/trekhleb/weighted-random-algorithm-in-javascript-1pdc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;ℹ️ Examples are from the &lt;a href="https://github.com/trekhleb/javascript-algorithms" rel="noopener noreferrer"&gt;javascript-algorithms&lt;/a&gt; repository&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is "Weighted Random"
&lt;/h2&gt;

&lt;p&gt;Let's say you have a list of &lt;strong&gt;items&lt;/strong&gt;. Item could be anything. For example, we may have a list of fruits and vegetables that you like to eat: &lt;code&gt;[ '🍌', '🍎', '🥕' ]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The list of &lt;strong&gt;weights&lt;/strong&gt; represent the weight (or probability, or importance) of each item. Weights are numbers. For example, the weights like &lt;code&gt;[3, 7, 1]&lt;/code&gt; would say that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you would like to eat &lt;code&gt;🍎 apples&lt;/code&gt; more often (&lt;code&gt;7&lt;/code&gt; out of &lt;code&gt;3 + 7 + 1 = 11&lt;/code&gt; times),&lt;/li&gt;
&lt;li&gt;then you would like to eat &lt;code&gt;bananas 🍌&lt;/code&gt; less often (only &lt;code&gt;3&lt;/code&gt; out of &lt;code&gt;11&lt;/code&gt; times),&lt;/li&gt;
&lt;li&gt;and the &lt;code&gt;carrots 🥕&lt;/code&gt; you really don't like (want to eat it only &lt;code&gt;1&lt;/code&gt; out of &lt;code&gt;11&lt;/code&gt; times).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If we speak in terms of probabilities than the weights list might be an array of floats that sum up to &lt;code&gt;1&lt;/code&gt; (i.e. &lt;code&gt;[0.1, 0.5, 0.2, 0.2]&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;strong&gt;Weighted Random&lt;/strong&gt; in this case will be the function that will randomly return you the item from the list, and it will take each item's weight into account, so that items with the higher weight will be picked more often.&lt;/p&gt;

&lt;p&gt;Example of the function interface:&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;items&lt;/span&gt; &lt;span class="o"&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;🍌&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;🍎&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;🥕&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;weights&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;7&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;weightedRandom&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="nx"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// implementation goes here ...&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;nextSnackToEat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;weightedRandom&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="nx"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Could be '🍎'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Applications of Weighted Random
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;a href="https://en.wikipedia.org/wiki/Genetic_algorithm" rel="noopener noreferrer"&gt;Genetic Algorithm&lt;/a&gt; the weighted random is used during the "Selection" phase, when we need to select the fittest/strongest individuums based on their fitness score for mating and for producing the next stronger generation. You may find an &lt;strong&gt;example&lt;/strong&gt; in the &lt;a href="https://trekhleb.dev/blog/2021/self-parking-car-evolution/" rel="noopener noreferrer"&gt;Self-Parking Car in 500 Lines of Code&lt;/a&gt; article.&lt;/li&gt;
&lt;li&gt;In &lt;a href="https://en.wikipedia.org/wiki/Recurrent_neural_network" rel="noopener noreferrer"&gt;Recurrent Neural Networks (RNN)&lt;/a&gt; when trying to decide what letter to choose next (to form the sentence) based on the next letter probability. You may find an &lt;strong&gt;example&lt;/strong&gt; in the &lt;a href="https://nbviewer.org/github/trekhleb/machine-learning-experiments/blob/master/experiments/recipe_generation_rnn/recipe_generation_rnn.ipynb" rel="noopener noreferrer"&gt;Recipe Generation using Recurrent Neural Network (RNN)&lt;/a&gt; Jupyter notebook.&lt;/li&gt;
&lt;li&gt;In &lt;a href="https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/" rel="noopener noreferrer"&gt;Nginx Load Balancing&lt;/a&gt; to send HTTP requests more often to the servers with the higher weights.&lt;/li&gt;
&lt;li&gt;And more...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Algorithm
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;straightforward approach&lt;/strong&gt; would be to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Repeat each item in the list according to its weight.&lt;/li&gt;
&lt;li&gt;Pick the random item from the list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example in our case with fruits and vegetables we could generate the following list of size &lt;code&gt;3 + 7 + 1 = 11&lt;/code&gt;:&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;items&lt;/span&gt; &lt;span class="o"&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;🍌&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;🍎&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;🥕&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;weights&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;7&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="c1"&gt;// Repeating the items based on weights.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weightedItems&lt;/span&gt; &lt;span class="o"&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;🍌&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;🍌&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;🍌&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;🍎&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;🍎&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;🍎&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;🍎&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;🍎&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;🍎&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;🍎&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;🥕&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="c1"&gt;// And now just pick the random item from weightedItems array.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, as you may see, this approach may require a lot of memory, in case if the objects are heavy, and in case if we have a lot of them to repeat in &lt;code&gt;weightedItems&lt;/code&gt; list.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;more efficient approach&lt;/strong&gt; would be to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prepare the list of cumulative weights for each item (i.e. the &lt;code&gt;cumulativeWeights&lt;/code&gt; list which will have the same number of elements as the original &lt;code&gt;weights&lt;/code&gt; list). In our case it will look like this: &lt;code&gt;cumulativeWeights = [3, 3 + 7, 3 + 7 + 1] = [3, 10, 11]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generate the random number &lt;code&gt;randomNumber&lt;/code&gt; from &lt;code&gt;0&lt;/code&gt; to the highest cumulative weight value. In our case the random number will be in a range of &lt;code&gt;[0..11]&lt;/code&gt;. Let's say that we have &lt;code&gt;randomNumber = 8&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go through the &lt;code&gt;cumulativeWeights&lt;/code&gt; list from left to right and pick the first element which is higher or equal to the &lt;code&gt;randomNumber&lt;/code&gt;. The index of such element we will use to pick the item from the &lt;code&gt;items&lt;/code&gt; array.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The idea behind this approach is that the higher weights will "occupy" more numeric space. Therefore, there is a higher chance that the random number will fall into the "higher weight numeric bucket".&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;weights&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;7&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cumulativeWeights&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// In a pseudo-representation we may think about the cumulativeWeights array like this.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pseudoCumulativeWeights&lt;/span&gt; &lt;span class="o"&gt;=&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="c1"&gt;// &amp;lt;-- [3] numbers&lt;/span&gt;
  &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&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;// &amp;lt;-- [7] numbers&lt;/span&gt;
  &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                    &lt;span class="c1"&gt;// &amp;lt;-- [1] number&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is an example of how the &lt;code&gt;weightedRandom&lt;/code&gt; function might be implemented:&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="cm"&gt;/**
 * Picks the random item based on its weight.
 * The items with higher weight will be picked more often (with a higher probability).
 *
 * For example:
 * - items = ['banana', 'orange', 'apple']
 * - weights = [0, 0.2, 0.8]
 * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return
 * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)
 *
 * @param {any[]} items
 * @param {number[]} weights
 * @returns {{item: any, index: number}}
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;weightedRandom&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="nx"&gt;weights&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;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;weights&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&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;Items and weights must be of the same size&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;items&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&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;Items must not be empty&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="c1"&gt;// Preparing the cumulative weights array.&lt;/span&gt;
  &lt;span class="c1"&gt;// For example:&lt;/span&gt;
  &lt;span class="c1"&gt;// - weights = [1, 4, 3]&lt;/span&gt;
  &lt;span class="c1"&gt;// - cumulativeWeights = [1, 5, 8]&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cumulativeWeights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;weights&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="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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cumulativeWeights&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;weights&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="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cumulativeWeights&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="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="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Getting the random number in a range of [0...sum(weights)]&lt;/span&gt;
  &lt;span class="c1"&gt;// For example:&lt;/span&gt;
  &lt;span class="c1"&gt;// - weights = [1, 4, 3]&lt;/span&gt;
  &lt;span class="c1"&gt;// - maxCumulativeWeight = 8&lt;/span&gt;
  &lt;span class="c1"&gt;// - range for the random number is [0...8]&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxCumulativeWeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cumulativeWeights&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cumulativeWeights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;maxCumulativeWeight&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="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Picking the random item based on its weight.&lt;/span&gt;
  &lt;span class="c1"&gt;// The items with higher weight will be picked more often.&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;itemIndex&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="nx"&gt;itemIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;items&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="nx"&gt;itemIndex&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="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;cumulativeWeights&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;itemIndex&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;randomNumber&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;item&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="nx"&gt;itemIndex&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;itemIndex&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check the &lt;a href="https://github.com/trekhleb/javascript-algorithms/blob/master/src/algorithms/statistics/weighted-random/weightedRandom.js" rel="noopener noreferrer"&gt;weightedRandom.js&lt;/a&gt; file for the implementation of the &lt;code&gt;weightedRandom()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Check the &lt;a href="https://github.com/trekhleb/javascript-algorithms/blob/master/src/algorithms/statistics/weighted-random/__test__/weightedRandom.test.js" rel="noopener noreferrer"&gt;weightedRandom.test.js&lt;/a&gt; file for the tests-cases.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>javascript</category>
      <category>algorithms</category>
      <category>computerscience</category>
    </item>
  </channel>
</rss>
