<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Xetera]]></title><description><![CDATA[A place for my ramblings.]]></description><link>https://xetera.dev</link><image><url>https://xetera.dev/favicon-32x32.png</url><title>Xetera</title><link>https://xetera.dev</link></image><generator>GatsbyJS</generator><lastBuildDate>Mon, 17 Jul 2023 15:37:40 GMT</lastBuildDate><atom:link href="https://xetera.dev/rss.xml" rel="self" type="application/rss+xml"/><item><title><![CDATA[🔭 Building a scalable scraper]]></title><link>https://xetera.dev/building-a-scalable-scraper/</link><guid isPermaLink="false">https://xetera.dev/building-a-scalable-scraper/</guid><pubDate>Sat, 25 Dec 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/building-a-scalable-scraper/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;div href=&quot;https://github.com/xetera/jiu&quot; target=&quot;_blank&quot;&gt;&lt;div sx=&quot;[object Object]&quot; src=&quot;https://opengraph.githubassets.com/1/Xetera/jiu&quot; borderradius=&quot;md&quot; width=&quot;full&quot; mx=&quot;auto&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div my=&quot;8&quot; mt=&quot;8&quot;&gt;&lt;/div&gt;&lt;p&gt;For the past year, I’ve been working on a website for Kpop image aggregation and labeling called &lt;a href=&quot;https://kiyomi.io&quot;&gt;Kiyomi&lt;/a&gt;. I’m interested in imageboards like &lt;a href=&quot;https://safebooru.org/&quot; target=&quot;_blank&quot; rel=&quot;noreferrer&quot;&gt;Safebooru&lt;/a&gt; that have an active community of fans who label every anime image to make searching easy for everyone. I love seeing how members come together to create a massive database of carefully curated content, and it’s only possible because of how much diverse content there is for the community to go through. For that reason, one of the challenges in working on Kiyomi has been to make sure that I can get fresh content to users automatically. Thankfully, there’s nothing Kpop idols love more than posting images of themselves online, so there’s an endless source of relevant material to work with.&lt;/p&gt;&lt;p&gt;I decided to solve this with what I know best, a scraper that I named &lt;strong&gt;Jiu&lt;/strong&gt; after one of the top 7 &lt;a href=&quot;https://www.youtube.com/watch?v=PEKkdIT8JPM&quot;&gt;Dreamcatcher&lt;/a&gt; members. In case you’re not familiar, scraping is a way of programmatically going to a website and extracting some kind of information from it. In my case, this information is image URLs and their associated metadata.&lt;/p&gt;&lt;p&gt;Normally this kind of image retrieval task is trivial to work with if all you need to check is a handful of pages on a single site. It’s nothing more than a &lt;/p&gt;&lt;div&gt;for&lt;/div&gt; loop, some database lookups, and a bunch of HTTP requests. But I was planning on scraping many websites, which meant the solution had to be easily extendable to support new sites. I also had to consider another thing, which is that I don’t wanna like… be an asshole? I don’t like it when devs carelessly hammer my website with requests. So given the nature of what I’m doing, it would be pretty hypocritical of me to try to do the same for others. This meant that while working on this service, I first had to exhaust all of the “good guy” workarounds before I moved on to less-friendly measures like rotating IPs and pretending to be a real user with puppeteer.&lt;p&gt;&lt;/p&gt;&lt;div&gt;Also, proxies that work well are expensive, and I&apos;m cheap&lt;/div&gt;&lt;p&gt;This project was originally meant to be a part of Kiyomi, but I figured the problem of finding images online was generic enough that it could be &lt;/p&gt;&lt;div href=&quot;https://github.com/xetera/jiu&quot; target=&quot;_blank&quot;&gt;its own standalone thing&lt;/div&gt;. Solving some of these problems has been incredibly fun and a huge learning process for me, so I’d like to document at least some of the ways I dealt with them.&lt;p&gt;&lt;/p&gt;&lt;h2 id=&quot;the-problem-space&quot;&gt;&lt;a href=&quot;https://xetera.dev/#the-problem-space&quot;&gt;The problem space&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This isn’t crucial to understanding the problem, but I want to share the infrastructure Jiu sits on top of because it could provide important context. Also, I spent a lot of time working on this and drawing the diagram for it, so I’m going to need someone to look at it.&lt;/p&gt;&lt;div caption=&quot;Kiyomi architecture map&quot;&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/4bd614220cb04bd6a05d667b6d5ca3e5/2dc7d/kiyomi_arch.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:50.8%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABU0lEQVQozzWRWZLbMAxEdYIxCaCxkaJiS6qZVO5/v4S0875QBBpLcyMmFhEFUbXs4/rdn7daEHHbx3nd53U/XyfUBCpQqB3OR7AnNmKGqzZjiLn31jKCaVJKeSxKeRBVIqq1Avg54s8zzl23WVXpDQvUrGVGRO89MkSEF++CWgszXu3a8xcztlo/0kpVAFtkpC+YudRa6qwCEBGqxjS7CctmZiICJghBtfU+xsA6rmUzte44UhXoC6gRfRbZWmtm5qCmdQYRLXMO8biua+97mHV3Nz/PMzNZMMVr3bk2A2i91MoCXkeKSCXuLsL0VcqjlK9SBBhjmMdMzwxtVCvM8vlSdzUX4O3Po9Tvww28mz8zz9YcKKWIQCNgxsxLDOz7PrtGfGxnFqBlmOkR6YADWNME2iP79FKWePq0t9Y8U/4TEfd9jzEUoPd3rXdV82zu+W/yX56jNGN5D585AAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/4bd614220cb04bd6a05d667b6d5ca3e5/490da/kiyomi_arch.webp 250w,/static/4bd614220cb04bd6a05d667b6d5ca3e5/e333e/kiyomi_arch.webp 500w,/static/4bd614220cb04bd6a05d667b6d5ca3e5/54609/kiyomi_arch.webp 1000w,/static/4bd614220cb04bd6a05d667b6d5ca3e5/de0ca/kiyomi_arch.webp 1500w,/static/4bd614220cb04bd6a05d667b6d5ca3e5/1716c/kiyomi_arch.webp 1760w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/4bd614220cb04bd6a05d667b6d5ca3e5/63868/kiyomi_arch.png 250w,/static/4bd614220cb04bd6a05d667b6d5ca3e5/0b533/kiyomi_arch.png 500w,/static/4bd614220cb04bd6a05d667b6d5ca3e5/00d43/kiyomi_arch.png 1000w,/static/4bd614220cb04bd6a05d667b6d5ca3e5/aa440/kiyomi_arch.png 1500w,/static/4bd614220cb04bd6a05d667b6d5ca3e5/2dc7d/kiyomi_arch.png 1760w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/4bd614220cb04bd6a05d667b6d5ca3e5/00d43/kiyomi_arch.png&quot; alt=&quot;kiyomi arch&quot; title=&quot;kiyomi arch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/div&gt;&lt;p&gt;New images Jiu finds on supported sites are stored in a database isolated from every other service and get published to RabbitMQ for consumers to do whatever with. Jiu also runs its own webserver to allow dynamically adding and removing new providers, querying the stats of scrapes, and displaying its schedule/history.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/edc3932389f1440c61a6dd715a7ea45e/0940f/scrape_schedule.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:72.8%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB3ElEQVQoz32TW2/eIAyGc78vwRjwgUPIoclaVbv6/v9/m4Cq7bRpEkLEwfbzvk6mut/n9X6//kplB2T0ap38vdCrsbRA+L6mUl/283XdrlSOWI6YNk1bzG3nWGNuZ0lVcys9Gz8b/5UsaUvl+PGwj8U9Fj9DmE14LG423lieTRi3xw5ODPICwSAbCBNpZa0kxVhegDjtaT2N5cAl1xuwAZf9J8lqLGs5vRRALtvtQpxYynG9xXK0ejawrrm+OErodXBiiGW7OFZAsaiz8dbJul0Y4mSlsq6j7QI0POtswx4ytkXAST9/BK1r/k3u7ZnL8WVDf90Fd4X98dNncAJd8wI0Gz8R5cDl8x43/06wFKTEejVUp2W/QzdF8+m5OMq53ujj5Ns8DvRxdECvnvKYbStnWjfP2YUIloYL1kng0pLl+azbZZC+YdNQYf+H3aRNQUqQgk57TiCtErcFyFHScgIKoMT1xVFegCTtnjKGpPkAlMlTjnnXtBvbzPQhsVb0ik7AfkByrIEzIAPKGB7H6kJqn2fdb2Ppsfg/sO3HPAb2PLA7yKeQidOmeUcf23iBSAZ2aGz/xOZmeywnep0cpZgP7eTWqaPEsfZ/S22DDNaLdGzTWFoEkCVu1slvI85Mhn06jvUAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/edc3932389f1440c61a6dd715a7ea45e/490da/scrape_schedule.webp 250w,/static/edc3932389f1440c61a6dd715a7ea45e/e333e/scrape_schedule.webp 500w,/static/edc3932389f1440c61a6dd715a7ea45e/54609/scrape_schedule.webp 1000w,/static/edc3932389f1440c61a6dd715a7ea45e/c5fa4/scrape_schedule.webp 1154w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/edc3932389f1440c61a6dd715a7ea45e/63868/scrape_schedule.png 250w,/static/edc3932389f1440c61a6dd715a7ea45e/0b533/scrape_schedule.png 500w,/static/edc3932389f1440c61a6dd715a7ea45e/00d43/scrape_schedule.png 1000w,/static/edc3932389f1440c61a6dd715a7ea45e/0940f/scrape_schedule.png 1154w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/edc3932389f1440c61a6dd715a7ea45e/00d43/scrape_schedule.png&quot; alt=&quot;scrape schedule&quot; title=&quot;scrape schedule&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;The requirements for building this scraper are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Creating a “plugin” system capable of supporting multiple social media sites&lt;/li&gt;&lt;li&gt;Turning polling into an event-based system with webhooks/AMQP&lt;/li&gt;&lt;li&gt;Automatically logging in to sites that require authentication&lt;/li&gt;&lt;li&gt;Being able to handle failure from APIs gracefully&lt;/li&gt;&lt;li&gt;Finding a high volume of images from different sites&lt;/li&gt;&lt;li&gt;Being nice and not sending too many requests to any specific site (if possible)&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;h2 id=&quot;i-am-scraping-respectfully&quot;&gt;&lt;a href=&quot;https://xetera.dev/#i-am-scraping-respectfully&quot;&gt;I am scraping respectfully&lt;/a&gt;&lt;/h2&gt;&lt;div as=&quot;img&quot; mt=&quot;2&quot; ml=&quot;4&quot; mb=&quot;4,,unset&quot; float=&quot;unset,,right&quot; src=&quot;https://i.kym-cdn.com/photos/images/original/001/936/074/bb8.png&quot; width=&quot;120px&quot;&gt;&lt;/div&gt;&lt;p&gt;The easiest way to prevent spamming a server with requests is to just not send it many requests, duh. This is an obvious one, but it’s something that works surprisingly well for what we’re building. Because the point of Jiu is to &lt;/p&gt;&lt;div color=&quot;green.400&quot; text=&quot;eventually&quot;&gt;It’s pronounced “eventual consistency”, not “wow this program is so slow wtf?”&lt;/div&gt; detect all images posted on social media and not as soon as possible. We can use this to our advantage when deciding the architecture of the scraper.&lt;p&gt;&lt;/p&gt;&lt;p&gt;A common way of implementing these scrapers is something commonly referred to as a monitor. A monitor takes one or a handful of critical pages and bombards it with requests to detect a change as soon as possible.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:551px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/ff466a38eeaf13efa4fd8e55ff5d2115/db783/monitor.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:98%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACjklEQVQ4y33U2XLkJhQG4LlPBrGjjR3EJvVud1Xy/u+VtHrcjitOVP8FF3x14AD6gT8+iDH6CETo/4MQwhj/eOGJs4mRiZGZM93330b1vRRCCjFyjp4YYcwI9rPO/tjiZbGVE9wzLhgTlH4NE5T1jNthQK/KFMPiV6urEFNL95/gtw52e8BrLwgh0IE9P1XfvzBhBFXX5tFihJI/6zm0dC/x5nQB4HcIOwgBxrjEtxxvdXmbOfu1ZwghgaD5Vc6eEJrjNYezlmEadApnNfk13ZM/jYPK4cJZ35Z3KfgDQ9hZ542SxVYlIyG0LrcUztOgOBPBros79f3sdI3u4HRBCCZ/+rVsAEBc0nFbk85KRvrAbyVe5WQ564PdvGmEUDWHYFdvGsY4h4vqBdorw2mWzqhqq5YLJbSl97rc5OQe2LRgD4zy73EHwJJzXkIxRatECV3T/YWdqYs7Msrl5L/ij2X7sKy1FFPMjlu61/jEwumS/ZkxIUcXzBrs+sT6iTsAtLE15yfeG/b2BYcLY2Ierf83BgDUtraas85aLoTQEm+vhu34/MTfVEYIzVIOgjfX9qMiJV6TP8+j2XFN/vSflfdLgjAELWzPbudwWdxxGkzPB29a8ifOejk5/+j8hjEp4aKHD0wIIahb/SYnByFY/CnYtRcjo2y/JAdC8DyaYNdg2mOCO5rh825jjLriWonviz+V+G51TfGa49XbLcVritc1/2FUruludT2UP3UvPt8zwdiNYzKp+c2MUg9zUmlRUYnBDDLp5KWbhYgqFFeidKb/Z2WMKSEEI4wgglBJ2VpNS3TWttYO26aVJAhRggmGBCOyk0/8fLTPAaF0mqVUmgsxzY8R4xzu/57XtL/xXx+Hg+FXvXp2AAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/ff466a38eeaf13efa4fd8e55ff5d2115/490da/monitor.webp 250w,/static/ff466a38eeaf13efa4fd8e55ff5d2115/e333e/monitor.webp 500w,/static/ff466a38eeaf13efa4fd8e55ff5d2115/72c8e/monitor.webp 551w&quot; sizes=&quot;(max-width: 551px) 100vw, 551px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/ff466a38eeaf13efa4fd8e55ff5d2115/63868/monitor.png 250w,/static/ff466a38eeaf13efa4fd8e55ff5d2115/0b533/monitor.png 500w,/static/ff466a38eeaf13efa4fd8e55ff5d2115/db783/monitor.png 551w&quot; sizes=&quot;(max-width: 551px) 100vw, 551px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/ff466a38eeaf13efa4fd8e55ff5d2115/db783/monitor.png&quot; alt=&quot;monitor&quot; title=&quot;monitor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;This is useful for reacting to changes made in a website quickly, but it’s not that important for this specific use case. Instead, the goal here is to detect changes across &lt;/p&gt;&lt;div&gt;every&lt;/div&gt; social media account that posts about Kpop, but in a sustainable way (aka slowly). So we want the same volume of requests, just spread out thinner over time and across significantly more pages.&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:551px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/d5926b2a60c2214ac04c63dc9d0ce656/db783/slow_monitor.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:94.39999999999999%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAIAAAAf7rriAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABmUlEQVQ4y52UW28bIRCF81w1NgwDAwvLZcG73ovjuEqbSJaqtv//R1Xe3baWmkiJj84DQvNxEAzcwSwhhEK8tryyes0AcAcAjPNojNfaEl2s1JsmcnNBsVYhXmA+w8sq79GGsZqIVhggGYNCcHiXGOdB6xXebrc3wlLKkFK8DSaiL09fl2T4KIyIuZSmqm6BiehwPN6YrC7b/nZjMiKOh0O2FgE+DBtjnp5fotZ/kt/KF69tWylX+6AJBc7dxq5Ll5Za5pfBMvJrk3C+NMlSrlUlhJiXuEyQMoiKsa0mqyShkFIS46wmrf62ZzSm0vZ+87krJ++ykgTA7zefchxLnAD4Q3+ujNdkd+nIOHOkVpgxVlwY2+fg94f+/Dj9fBi+N3F0VSrpOPXnsXt5HH/UrtS2nKZfu3zyxioU66vy2kTrd6HNvjQuZdf0aWx9l11uXE42JZtyXdq4b0PXxn3nGxTze14kBQjOELgUgMBqa4Z913dtE8M0DIdxaGJAzqTgs2H9DP4XB0CUrvYpNUTah+hDJNLzef+7s98OdWNuzYcqdQAAAABJRU5ErkJggg==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/d5926b2a60c2214ac04c63dc9d0ce656/490da/slow_monitor.webp 250w,/static/d5926b2a60c2214ac04c63dc9d0ce656/e333e/slow_monitor.webp 500w,/static/d5926b2a60c2214ac04c63dc9d0ce656/72c8e/slow_monitor.webp 551w&quot; sizes=&quot;(max-width: 551px) 100vw, 551px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/d5926b2a60c2214ac04c63dc9d0ce656/63868/slow_monitor.png 250w,/static/d5926b2a60c2214ac04c63dc9d0ce656/0b533/slow_monitor.png 500w,/static/d5926b2a60c2214ac04c63dc9d0ce656/db783/slow_monitor.png 551w&quot; sizes=&quot;(max-width: 551px) 100vw, 551px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/d5926b2a60c2214ac04c63dc9d0ce656/db783/slow_monitor.png&quot; alt=&quot;slow monitor&quot; title=&quot;slow monitor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h2 id=&quot;priority&quot;&gt;&lt;a href=&quot;https://xetera.dev/#priority&quot;&gt;Priority&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Something important to recognize is that not all pages are created the same. There are accounts that consistently post good content, usually ran by companies behind groups; these should be checked frequently. There are also accounts that post infrequently, or post second-hand content (like with fan accounts); these should be checked less frequently. This requirement calls for implementing a priority system where different pages can automatically adjust their priority depending on the post frequency, on top of a manual multiplier if needed.&lt;/p&gt;&lt;p&gt;Originally, I went for a dynamic priority system where tasks would get re-scheduled based on how many images they found as they moved up and down on a discrete priority scale. The highest priority scrapes would get scheduled for 4 hours after a request, and the lowest would get two weeks. This worked well for changing scrape frequencies dynamically, but it created an issue with scrape distribution. It allowed multiple scheduled scrapes to fall within the same hour and get the bot rate limited by accident. This is unlikely with only a few endpoints but would become more and more likely as the app scaled, and that’s a problem.&lt;/p&gt;&lt;p&gt;I played around with some numbers and re-scheduling details, but the problem here was scheduling itself. I had to completely re-think how I approached it. In the end, I went with something similar to a &lt;a href=&quot;https://en.wikipedia.org/wiki/Token_bucket&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;token bucket&lt;/a&gt;, often used for rate limiting algorithms. Every page/account has a bucket of tokens and a rate in which it gains new tokens (called &lt;/p&gt;&lt;div&gt;priority&lt;/div&gt;). At the start of every day, their tokens get updated by their priority. If a page has more than one token, they get scheduled one scrape per token &lt;div&gt;sometime&lt;/div&gt; within the next 24 hours, and that amount gets subtracted from their tokens.&lt;p&gt;&lt;/p&gt;&lt;p&gt;At the start of the day, a database that looks like the following will get these tasks scheduled.&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Provider Type&lt;/th&gt;&lt;th&gt;Priority&lt;/th&gt;&lt;th&gt;Tokens&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;1.0&lt;/td&gt;&lt;td&gt;2.0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;1.0&lt;/td&gt;&lt;td&gt;2.2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;0.5&lt;/td&gt;&lt;td&gt;2.5&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div caption=&quot;Example list of scheduled scrapes&quot;&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/e2bb0/bad_distribution.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:19.2%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAsUlEQVQI1y3LSXKDMBAAQD5g55CYaEGzS0KDBc7/P5cql/veixM7y1CzUgbx7HtWXhmDEJhGoQeVrEKyA3VSF+sbVmBHbouHcAG8eh8pnSn/WV2FbhC/FZPJF6Y7plQF5QhlzzisnxFGoknqy4zxLGW2dm3bTPnJ8mC4YfoR2JrdP1lBZij+zlcEj+DAfTlFT7XD6pN4AA7VaLIK5qrUWxD6FYJWrU2yieqsO4ijHoXsH8vHH0K/yVATAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/490da/bad_distribution.webp 250w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/e333e/bad_distribution.webp 500w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/54609/bad_distribution.webp 1000w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/de0ca/bad_distribution.webp 1500w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/ef7fd/bad_distribution.webp 1667w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/63868/bad_distribution.png 250w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/0b533/bad_distribution.png 500w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/00d43/bad_distribution.png 1000w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/aa440/bad_distribution.png 1500w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/e2bb0/bad_distribution.png 1667w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/00d43/bad_distribution.png&quot; alt=&quot;bad distribution&quot; title=&quot;bad distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/div&gt;&lt;p&gt;After every successful scrape, the next priority of the provider is calculated by getting the latest scrape result + the past 30 scrapes, and summing up the amount of images it found per check, weighed by how long ago the scrape was from the current day.&lt;/p&gt;&lt;div caption=&quot;Example list of scheduled scrapes&quot;&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/72253fab2999eae65fa39f5df72423d6/2ed34/priority_graph.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:41.6%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAABHklEQVQY02VQbY7lIAzrDR4BQr4gpZ3C65v7H3BEpV2tdiIrf2LHsrcYY4qxlagYG60NAIg45/x8Ptd1jTHO84y/B2BDRHffj6MILzBn4kyUC6VCmSghplKQBUWeE+fFoVJ9s1pTxut9l5zDf79TAgAiRkQRFVEA+GubWbbej5SzX4MxY1oR/lWLSK2VWYhY1QAg/RGj2RLHlPYxc86mqkQ5Ql5FLJN978y8cvUuIq/XCx53CAHVNve9ubevi5lFzWrrvbdaTbVV+zpPb3WOMcf01phImKkURuTWVmFmtV/juu9zvnXv2g/pXfohe2d3qpXdpe3mC36c7+/veX/mfW8AEELQJ5vqqgQgQAgxQm3NzJo7IoYQHubKYs+o6g9HsC280JGsqgAAAABJRU5ErkJggg==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/72253fab2999eae65fa39f5df72423d6/490da/priority_graph.webp 250w,/static/72253fab2999eae65fa39f5df72423d6/e333e/priority_graph.webp 500w,/static/72253fab2999eae65fa39f5df72423d6/54609/priority_graph.webp 1000w,/static/72253fab2999eae65fa39f5df72423d6/de0ca/priority_graph.webp 1500w,/static/72253fab2999eae65fa39f5df72423d6/48051/priority_graph.webp 1776w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/72253fab2999eae65fa39f5df72423d6/63868/priority_graph.png 250w,/static/72253fab2999eae65fa39f5df72423d6/0b533/priority_graph.png 500w,/static/72253fab2999eae65fa39f5df72423d6/00d43/priority_graph.png 1000w,/static/72253fab2999eae65fa39f5df72423d6/aa440/priority_graph.png 1500w,/static/72253fab2999eae65fa39f5df72423d6/2ed34/priority_graph.png 1776w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/72253fab2999eae65fa39f5df72423d6/00d43/priority_graph.png&quot; alt=&quot;priority graph&quot; title=&quot;priority graph&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/div&gt;&lt;p&gt;This makes sure that an inactive account that starts to post images gets a higher bump in priority, and an active account that stops posting images gets knocked down an equivalent amount.&lt;/p&gt;&lt;p&gt;When the tokens for a provider is under 1.0, it gets compounded by its priority every day even if it doesn’t get scraped. A priority can’t go below 0.07 &lt;/p&gt;&lt;div as=&quot;span&quot; color=&quot;text.400&quot;&gt;(meaning a scrape once every 2 weeks)&lt;/div&gt; and can’t go above 1.75 &lt;div as=&quot;span&quot; color=&quot;text.400&quot;&gt;(3 times every 2 days)&lt;/div&gt;.&lt;p&gt;&lt;/p&gt;&lt;h2 id=&quot;distribution&quot;&gt;&lt;a href=&quot;https://xetera.dev/#distribution&quot;&gt;Distribution&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Once all the tasks that need to run within the next 24 hours are identified, they need to be scheduled for an exact time with an even distribution. We can’t just blindly start going through all pages that need to be sent requests immediately, otherwise we run into the exact same rate limiting problem from before.&lt;/p&gt;&lt;p&gt;That day’s worth of pending requests need to be grouped by their provider type —think Instagram, Twitter, etc.— and scheduled in an evenly-spaced manner using a linear interpolation between &lt;/p&gt;&lt;div&gt;NOW()&lt;/div&gt; and &lt;div&gt;NOW() + 24 hours&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:987px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/f0cadfa0433c2e64669dd500b04cb2ac/d1d24/task_distribution.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:80.80000000000001%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAIAAACZeshMAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACP0lEQVQoz31TSY7jSAz0Bywl99wzlVpslavq0Kf5/8sGcs30oQ8NxIEMIBBgkLwhIhJZFsvCntjIAf4d8AYi3ogoBe1d1lW3XbchWbEYZoUepAfJBlkxCSbFqOgZjSF6IaKbF/rsVhTPVVaPW8Bz8FFo9fBa7WOxi2n8GrxH2gvtnbPBVzcvdAtKe7YJ0XeZAR2RJAah+wSaVLPdJwAhiXyfEYQ08h3wUS0o3bzSoygQ5ibEKIIxsxohQCoWiyGADxyrICILxcyAeFb9T7y9nUOR2SHw5YxC0wwa1ZJOM5Bdic6AyFcxAR7lLVaho1hUHI2rUQ+0NR6JmsfHsKNrUxyJ1srVsAZaGgeFRzUTeqftNQoUw+axe1o8LYG6xzXpmqR77FdLzVM1yopRIHu90iYiNUv9Y5z/hHrMDhzg7GB2QCzEMs3uh7zgHCA6ANG3mJm2Yt3DUcPZ85Hwmelria8qX/3C94jfS3gVfBX6XstZ5Ij4rMb8nrklm52zUELZHACJpfZgjUTEIrEeFruD66j6/ovFJueW9J7ZhEa2eXY+Np8awCzqY9lYPTOJaIjdx4Z4HWQdnyKX017M6//iaXY+dQvVgWONsWzESsws6tOw2AERAFI9WOz+W6xMIxmCy6XXthpBMO19D957oWBcy1JLVwJjXJZnMCV0W1ZlujHxkmwE3BM/izwznhk/roJeTV9Nn4XPIueb/2x2FjoSblmZ+ZZzOR6n+TjN7vfTXbtBWtat9vEH/7PCdT+WZfwLuulZPqhioYIAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/f0cadfa0433c2e64669dd500b04cb2ac/490da/task_distribution.webp 250w,/static/f0cadfa0433c2e64669dd500b04cb2ac/e333e/task_distribution.webp 500w,/static/f0cadfa0433c2e64669dd500b04cb2ac/5a8c7/task_distribution.webp 987w&quot; sizes=&quot;(max-width: 987px) 100vw, 987px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/f0cadfa0433c2e64669dd500b04cb2ac/63868/task_distribution.png 250w,/static/f0cadfa0433c2e64669dd500b04cb2ac/0b533/task_distribution.png 500w,/static/f0cadfa0433c2e64669dd500b04cb2ac/d1d24/task_distribution.png 987w&quot; sizes=&quot;(max-width: 987px) 100vw, 987px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/f0cadfa0433c2e64669dd500b04cb2ac/d1d24/task_distribution.png&quot; alt=&quot;task distribution&quot; title=&quot;task distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* scheduling algorithms be like */
.pending-requests {
  display: flex;
  justify-content: space-evenly;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This method of scheduling ensures that pages on different domains that don’t share rate limits are processed concurrently, while pages that do share a rate limit get processed sequentially.&lt;/p&gt;&lt;p&gt;With what we know now, let’s take another look at the scheduled tasks from last time and imagine each letter is an individual Twitter page, each scheduled to get processed at an even interval after the other.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/e2bb0/bad_distribution.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:19.2%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAsUlEQVQI1y3LSXKDMBAAQD5g55CYaEGzS0KDBc7/P5cql/veixM7y1CzUgbx7HtWXhmDEJhGoQeVrEKyA3VSF+sbVmBHbouHcAG8eh8pnSn/WV2FbhC/FZPJF6Y7plQF5QhlzzisnxFGoknqy4zxLGW2dm3bTPnJ8mC4YfoR2JrdP1lBZij+zlcEj+DAfTlFT7XD6pN4AA7VaLIK5qrUWxD6FYJWrU2yieqsO4ijHoXsH8vHH0K/yVATAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/490da/bad_distribution.webp 250w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/e333e/bad_distribution.webp 500w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/54609/bad_distribution.webp 1000w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/de0ca/bad_distribution.webp 1500w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/ef7fd/bad_distribution.webp 1667w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/63868/bad_distribution.png 250w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/0b533/bad_distribution.png 500w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/00d43/bad_distribution.png 1000w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/aa440/bad_distribution.png 1500w,/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/e2bb0/bad_distribution.png 1667w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/6bbe0ca5953d5c3f2aeec0eb9d496b79/00d43/bad_distribution.png&quot; alt=&quot;example of a list of scheduled scrapes&quot; title=&quot;example of a list of scheduled scrapes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;div&gt;Can you spot the inefficiency here?&lt;/div&gt;&lt;p&gt;We’re scheduling the same page to be scraped multiple times right after each other. We’re making sure to space the scrapes within the same provider evenly but leaving uneven spaces between repeated scrapes.&lt;/p&gt;&lt;p&gt;The correct order of the tasks should be more like this:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/c47786eca1bdcc33a8518da6394472fe/6b26f/good_distribution.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:18.4%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAsUlEQVQI1wXB2wGDIAwAQBdo7VcRAUNeaAho95+ud8tD9GPxdgaum2BspDZJH6CB4k48a/0xm9lX8Cs1n8qtVx4g92Jx95RGO1fIHz7WupPdGWcEP8gH1DulpxTvfaWyYg4nU5vxGDv4cm7bTLmLviGtWD418TUT+A4D2EfFHuOdi1t/Y35RDoqkvpUrFlsuAKu1MQeEwBgIuBnqPKgDXkNkIN0sqhoEd6XcBKgdaMD+B1sFH+7EDq2AAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/c47786eca1bdcc33a8518da6394472fe/490da/good_distribution.webp 250w,/static/c47786eca1bdcc33a8518da6394472fe/e333e/good_distribution.webp 500w,/static/c47786eca1bdcc33a8518da6394472fe/54609/good_distribution.webp 1000w,/static/c47786eca1bdcc33a8518da6394472fe/de0ca/good_distribution.webp 1500w,/static/c47786eca1bdcc33a8518da6394472fe/3506a/good_distribution.webp 1658w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/c47786eca1bdcc33a8518da6394472fe/63868/good_distribution.png 250w,/static/c47786eca1bdcc33a8518da6394472fe/0b533/good_distribution.png 500w,/static/c47786eca1bdcc33a8518da6394472fe/00d43/good_distribution.png 1000w,/static/c47786eca1bdcc33a8518da6394472fe/aa440/good_distribution.png 1500w,/static/c47786eca1bdcc33a8518da6394472fe/6b26f/good_distribution.png 1658w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/c47786eca1bdcc33a8518da6394472fe/00d43/good_distribution.png&quot; alt=&quot;example of well-spaced provider distribution&quot; title=&quot;example of well-spaced provider distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;For this reason, Jiu tries its best to maximize the spacing between requests going to the same endpoint so that there’s enough time for content to update.&lt;/p&gt;&lt;p&gt;“Tries its best” because sadly &lt;a href=&quot;https://stackoverflow.com/questions/12375831/algorithm-to-separate-items-of-the-same-type&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;the solution&lt;/a&gt; to this problem is not simple or deterministic.&lt;/p&gt;&lt;h2 id=&quot;authentication&quot;&gt;&lt;a href=&quot;https://xetera.dev/#authentication&quot;&gt;Authentication&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Another unfortunate problem that must be dealt with is that not every single website lets us view images without being logged in. To be able to do this, the login flow of the site needs to be &lt;a href=&quot;https://gist.github.com/Xetera/aa59e84f3959a37c16a3309b5d9ab5a0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;reverse engineered&lt;/a&gt; in order to grab the necessary images. This also sometimes comes with the downside of needing to fake a user agent (or possibly other fingerprints).&lt;/p&gt;&lt;p&gt;Now, I know that reverse engineering and using a private API for fetching data and going outside the boundaries of what a site thinks is acceptable kind of contradicts wanting to be nice to websites and not spamming them. But using official APIs can get us rate-limited quickly, even with large gaps in requests. I’m going out of my way to be careful with the sites I’m scraping, so I deserve this. Besides, I know what’s best for Twitter more than Twitter knows what’s best for herself, and I promise I will treat her like the queen she is if she just gives me a chance.&lt;/p&gt;&lt;div as=&quot;video&quot; controls=&quot;&quot; maxh=&quot;600px&quot; margin=&quot;0 auto&quot; mb=&quot;3&quot;&gt;&lt;source src=&quot;static/nice_guy-45ebcb2dc461663aaf3c6ef435fc7f59.mp4&quot;&gt;&lt;/div&gt;&lt;div&gt;&lt;div href=&quot;https://vm.tiktok.com/ZM83u526w/&quot; target=&quot;_blank&quot; font-size=&quot;14px&quot;&gt;context&lt;/div&gt;&lt;/div&gt;&lt;h2 id=&quot;architecture-and-code&quot;&gt;&lt;a href=&quot;https://xetera.dev/#architecture-and-code&quot;&gt;Architecture and Code&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;For the more technical part, instead of copy-pasting functions from the codebase, I’m going to walk you through building a mini-scraper logic so you can maybe get a feel for what it would’ve been like to come up with some of the abstractions I haven’t mentioned yet on your own.&lt;/p&gt;&lt;p&gt;I wrote this program in Rust, but I’m going to use Typescript examples because it’s probably way more accessible for my audience. &lt;del&gt;Feel free to look at the Rust source if you’re interested&lt;/del&gt; In case you’re interested, do not feel free to look through my Rust code. Please just keep reading the examples. I will take legal action against anyone I catch browsing through the repo.&lt;/p&gt;&lt;p&gt;Let’s start with the most fundamental idea. A requirement for this project is that we need a solution that allows fetching different forms of media from many sites. One assumption we can make is that every image/video should conform to one shared interface no matter its source. At this point, one could go for a simple class that turns a URL into an array of images.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class Provider {
  constructor(public siteName: string) {}

  async scrape(url: string): Promise&amp;lt;Image[]&amp;gt; {
    const images = await this.request(url)
    return this.extractAllImages(images)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;Try to use your imagination for the functions I haven&apos;t defined&lt;/div&gt;&lt;p&gt;We should now account for the possibility that this is the first time we’re gathering data from that page and haven’t seen any images. We need to add a pagination concept so our scraper can go through the page history and grab everything.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{h:&amp;quot;3-16&amp;quot;}&quot;&gt;class Provider {
  async scrape(url: string): Promise&amp;lt;Image[]&amp;gt; {
    let target = url
    const images: Image[] = []
    while (true) {
      const response = await this.request(target)
      const pagination = this.getPagination(response)
      images.push(this.extractAllImages(response))
      if (pagination.hasNextPage) {
        // turns ?page=1 into ?page=2
        target = this.getNextPage(target)
      } else {
        break
      }
    }
    return images
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we have a way of getting all images from a website. Except, with this approach, we always paginate through the full resource for every check. We should be able to stop when we find an image we’ve seen before and only “gather” the ones we haven’t seen in a previous run. This can be solved by passing an array of previously seen images to the function to test against.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{h:&amp;quot;8-14&amp;quot;}&quot;&gt;class Provider {
  async scrape(url: string, seen: string[]): Promise&amp;lt;Image[]&amp;gt; {
    let target = url
    const images: Image[] = []
    while (true) {
      const response = await this.request(target)
      const pagination = this.getPagination(response)
      const found = this.extractAllImages(response)
      const unseen = this.allUnseenImages(found, seen)
      images.push(unseen)
      if (unseen.length !== found.length) {
        // some of the images we scraped were seen before
        break
      }
      if (pagination.hasNextPage) {
        // turns ?page=1 into ?page=2
        target = this.getNextPage(target)
      } else {
        break
      }
    }
    return images
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Great, it looks like this is working fine for one provider like Twitter, but it’s still not scalable. The entire point of the project was to implement a solution that can have multiple sites plugged into it, and every provider is going to require a different way of fetching and processing data. There’s a &lt;code&gt;Provider&lt;/code&gt; class here, but it’s not extensible in any way. We can’t configure the parts that need to be swapped out for different sites because everything gets done in a single function. Perhaps OOP is the right fix? Maybe all we need to do is extend &lt;code&gt;Provider&lt;/code&gt; and reuse the logic somehow.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class WeverseProvider extends Provider {
  override async scrape(url: string, seen: string[]): Promise&amp;lt;Image[]&amp;gt; {
    // ???
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But what exactly goes in this function now, literally everything we had in the previous class? Aside from &lt;code&gt;this.request&lt;/code&gt;, every single method on here is custom (mostly) per-provider and can’t just be overridden. It would be nice to have a way to almost… “template” a class method so that the &lt;code&gt;if&lt;/code&gt; checks —like the part where we look to see if we’ve reached the end of everything we’ve scraped— and &lt;code&gt;break&lt;/code&gt; statements stay, but everything else is customized.&lt;/p&gt;&lt;p&gt;As you may have guessed, there’s a way to do that. Well, not with templating, god no. That was a terrible call; what are you crazy? The issue is &lt;code&gt;Provider&lt;/code&gt; is trying to do way too much here, and it’s getting in our way. As a rule of thumb, when you run into a problem where you need to copy-paste &lt;/p&gt;&lt;div&gt;logic&lt;/div&gt;, creating reusable functions is usually the correct approach. However, when you run into problems where you need to copy-paste &lt;div&gt;control flow&lt;/div&gt;, the solution is getting rid of tight coupling.&lt;p&gt;&lt;/p&gt;&lt;p&gt;I mean, why does this class need to care at all about previously seen images? A provider’s scrape function only needs to scrape, and that’s it, no? It’s time to turn our single class method into a producer/consumer pair. Ideally, we need a producer that knows nothing about the outside world. And a consumer that only knows about the promise that a provider makes about what it’s capable of doing through an interface.&lt;/p&gt;&lt;p&gt;Let’s call the new class that will decouple that logic &lt;code&gt;Scraper&lt;/code&gt;, and clean up the function names to reflect the new responsibilities of the two.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class Scraper {
  async scrape(provider: Provider, url: string): Promise&amp;lt;Image[]&amp;gt; {
    const seen = await this.getLatestResultsFor(provider)
    const found = await provider.process(url)
    return provider.allUnseenImages(found, seen)
  }
}

class Provider {
  async process(url: string): Promise&amp;lt;Image[]&amp;gt; {
    const response = await this.request(target)
    return this.extractAllImages(response)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This works well for checking images. We can do something similar to re-implement pagination. Except, this time, the while loop can’t be inside the provider; it has to be inside &lt;code&gt;Scraper&lt;/code&gt;. The problem with that is the scraper doesn’t understand what pagination means. Most sites (like Weverse) use page-based pagination, where you increase page numbers by 1 to go to the next page. But there are also sites (like Pinterest &amp;amp; Twitter) that use a cursor-based pagination technique, where you pass the server some opaque identifier from request one that represents the next page for request two.&lt;/p&gt;&lt;p&gt;&lt;code&gt;Scraper&lt;/code&gt; shouldn’t have to know anything about how a provider’s pagination works, only that pagination is a thing that exists and needs to be passed back to a provider. &lt;code&gt;Provider&lt;/code&gt; needs to accept and return information about pagination so it can decide what page to scrape by itself.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class Scraper {
  async scrape(provider: Provider, url: string): Promise&amp;lt;Image[]&amp;gt; {
    const seen = await this.getLatestResultsFor(provider)
    // undefined in the initial iteration
    let pagination: Pagination | undefined
    let images: Image[] = []
    while (true) {
      const result = await provider.process(url, pagination)
      const unseen = provider.allUnseenImages(found, seen)
      images.push(unseen)
      if (unseen.length !== result.images.length) {
        break
      }
      if (result.nextPage) {
        pagination = result.nextPage
      } else {
        break
      }
    }
    return images
  }
}

type Pagination =
  | { type: &quot;cursor&quot;; id: string }
  | { type: &quot;page&quot;; index: number }

type ProviderResult = { images: Image[]; nextPage?: Pagination }

class Provider {
  async process(url: string, pagination?: Pagination): Promise&amp;lt;ProviderResult&amp;gt; {
    const target = this.buildUrlWithPagination(url, pagination)
    const response = await this.request(target)
    const images = this.extractAllImages(response)
    const nextPage = this.extractNextPage(response)

    return { images, nextPage }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This approach works perfectly! Though, the observant functional programmers &lt;/p&gt;&lt;div verticalalign=&quot;baseline&quot; alt=&quot;among us&quot; display=&quot;inline-block&quot; src=&quot;static/amogu-137e6fc391e12434a811866df63b31f3.png&quot; w=&quot;75px&quot;&gt;&lt;/div&gt; may have noticed that the thing we’re doing here looks awfully similar to &lt;div&gt;array.reduce&lt;/div&gt;. We’re going through a loop and feeding the result of a function call in one iteration (in our case, pagination) back into the function called in the next iteration, much like reduce. It could be useful to re-package iteration logic with a functional helper if it makes things easier to reason about.&lt;p&gt;&lt;/p&gt;&lt;p&gt;As a refresher, &lt;code&gt;reduce&lt;/code&gt; (also referred to as &lt;code&gt;fold&lt;/code&gt; in some languages) works by doing something like the following, where it takes an &lt;/p&gt;&lt;div&gt;A’&lt;/div&gt;, an array of values, and produces &lt;div&gt;E’&lt;/div&gt; as an output.&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/971f39e1666f714a45498d14df8711f1/5d36b/reduce.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:32%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA30lEQVQY0y2OUW7DMAxDewU7olyJkp02QdZh7fYz7P5HG5JUXwSEx8fL9+vvNm+AOp0MMszdne9szjiDmb+zk5NIrfXSF1pAm2QfqgrFyQDYC2LvUlU7rrWmqtm7nHAttZQiIiQV1wZnEKrp6z7HXdEadgz7O4HGCAAHPNVaq4j00d0iOLInydGXc6m7j7w7aWYZs3uQBFBKudT6NmfPdXls21dmjvn2ev6O+ZaZ9/v62J7ZO8nPj591eZibyGEupSgafaYPcperFQsduQDAtex+S8HUvGYOtxBU6xN0+gfIQCQ1Ft+eRQAAAABJRU5ErkJggg==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/971f39e1666f714a45498d14df8711f1/490da/reduce.webp 250w,/static/971f39e1666f714a45498d14df8711f1/e333e/reduce.webp 500w,/static/971f39e1666f714a45498d14df8711f1/54609/reduce.webp 1000w,/static/971f39e1666f714a45498d14df8711f1/c4383/reduce.webp 1467w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/971f39e1666f714a45498d14df8711f1/63868/reduce.png 250w,/static/971f39e1666f714a45498d14df8711f1/0b533/reduce.png 500w,/static/971f39e1666f714a45498d14df8711f1/00d43/reduce.png 1000w,/static/971f39e1666f714a45498d14df8711f1/5d36b/reduce.png 1467w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/971f39e1666f714a45498d14df8711f1/00d43/reduce.png&quot; alt=&quot;a diagram explaining how fold/reduce works&quot; title=&quot;a diagram explaining how fold/reduce works&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;But this doesn’t quite work for us. We have an initial seed value of a URL, yes. But we don’t have an array of things we can go over. Instead we want to &lt;/p&gt;&lt;div&gt;create&lt;/div&gt; that array of things &lt;div as=&quot;span&quot; color=&quot;text.400&quot;&gt;(image URLs)&lt;/div&gt; as a result of repeatedly applying a function &lt;div as=&quot;span&quot; color=&quot;text.400&quot;&gt;(scrape)&lt;/div&gt; on something &lt;div as=&quot;span&quot; color=&quot;text.400&quot;&gt;(pagination)&lt;/div&gt;. Almost like a fold, but the other way around. Thankfully the thing we’re looking for here is a well-known concept like &lt;code&gt;fold&lt;/code&gt; and is unsurprisingly called &lt;code&gt;unfold&lt;/code&gt;.&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/9545389ec01196b7a8e16f74f37caad4/c655d/unfold.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:25.6%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAz0lEQVQY0zVQSW7DMBDzC1pZkWaXRyPFRpq0h/7/c4UClOCJABdwe379qhxIZNasHe1N79F7eO8xZo9w94gRMdy7iBIzIiHRdn9MVhARQMy3TLzUW8m1AhHXWnPOiCiiOe+IWEpJbyDitu97SolZoAJIYmYRQ80kBSpVKAX2lceMtgNArfXfwlvO+TN9EJOqta5mutyHHGEsomZ9HqIqKuZqzWotKwFA1VazsPfjcu99+HW+rvMVM+ac53iOeY/Z53hc53eM9cI1f1pzxDXhDw0FHvWu/0uHAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/9545389ec01196b7a8e16f74f37caad4/490da/unfold.webp 250w,/static/9545389ec01196b7a8e16f74f37caad4/e333e/unfold.webp 500w,/static/9545389ec01196b7a8e16f74f37caad4/54609/unfold.webp 1000w,/static/9545389ec01196b7a8e16f74f37caad4/de0ca/unfold.webp 1500w,/static/9545389ec01196b7a8e16f74f37caad4/93331/unfold.webp 1586w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/9545389ec01196b7a8e16f74f37caad4/63868/unfold.png 250w,/static/9545389ec01196b7a8e16f74f37caad4/0b533/unfold.png 500w,/static/9545389ec01196b7a8e16f74f37caad4/00d43/unfold.png 1000w,/static/9545389ec01196b7a8e16f74f37caad4/aa440/unfold.png 1500w,/static/9545389ec01196b7a8e16f74f37caad4/c655d/unfold.png 1586w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/9545389ec01196b7a8e16f74f37caad4/00d43/unfold.png&quot; alt=&quot;a diagram explaining how unfold works&quot; title=&quot;a diagram explaining how unfold works&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;We start with an initial value &lt;/p&gt;&lt;div&gt;A’&lt;/div&gt; and produce two outputs, one as the value that will be “pushed” into an array and the other which will get passed as an argument into the next iteration.&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class Scraper {
  scrape(provider: Provider, url: string): AsyncGenerator&amp;lt;Image[]&amp;gt; {
    // initial value is `undefined` beceause
    // the first scrape has no pagination
    return unfold(undefined, async pagination =&amp;gt; {
      const result = await provider.process(url, pagination)
      if (result.nextPage) {
        return next(result.images, result.nextPage)
      } else {
        return stop(result.images)
      }
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The hypothetical &lt;/p&gt;&lt;div&gt;stop&lt;/div&gt; function here lets us signal the unfold to stop early if we’ve exhausted all resources. Typically, this would be done by returning an &lt;code&gt;Option&lt;/code&gt; data type in a language like Rust, but it’s hard to represent that as clearly in JS.&lt;p&gt;&lt;/p&gt;&lt;p&gt;This approach to iteration lets us decouple logic even further. Unlike &lt;code&gt;fold&lt;/code&gt; which reduces an iterable into a single value synchronously, &lt;code&gt;unfold&lt;/code&gt; generates an array of values. If the operation that is being run to generate values is asynchronous, that array can also be represented as an &lt;/p&gt;&lt;div&gt;infinite stream&lt;/div&gt; of values that a consumer can stop generating at any point. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;Async iterators&lt;/a&gt; are great for doing this in Javascript.&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const seen = await getLatestResultsFor(provider)
for await (const images of scraper.scrape(provider, url)) {
  const unseen = scraper.getUnseenImages(images, seen)
  if (unseen.length !== images.length) {
    // scraping stops here because the generator
    // is no longer being consumed
    break
  }
  await processImages(unseen)
  // delay the next iteration of the scrape
  // for 1 second
  await sleep(1000)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Since we’re using generators now, the scraper doesn’t need to know the conditions to look for to stop doing its job anymore; it stops when we tell it to stop inside the consumer (or runs out of pages). This means that if we wanted to, we could conveniently get the scraper to keep going even if it finds known images —like when re-fetching all images posted by a specific account— without touching the scraping logic.&lt;/p&gt;&lt;p&gt;Error handling and other related things can also be done now by enriching the return value of &lt;code&gt;process&lt;/code&gt; to include more information about what happened. A provider can accept an error &lt;em&gt;that it itself created in a different function&lt;/em&gt; and figure out how to deal with it without actually dealing with it to further decouple the process of handing off errors.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ProcessResult =
  | { type: &quot;success&quot;; result: ProviderResult }
  | { type: &quot;error&quot;; response: Response }

type ErrorHandle =
  | { type: &quot;tryAgain&quot; }
  | { type: &quot;tryAuth&quot; }
  | { type: &quot;cantContinue&quot;; reason: Error }

async function iterate(pagination?: Pagination) {
  const process = await provider.process(url, pagination)
  if (process.error) {
    const decision: ErrorHandle = await provider.onError(process.response)
    switch (decision.type) {
      case &quot;tryAgain&quot;:
        // retry logic with an unfold is nothing
        // more than recursion
        return iterate(pagination)
      case &quot;tryAuth&quot;:
        await provider.authenticate()
        return iterate(pagination)
      case &quot;cantContinue&quot;:
        // handle errors here :)
        return stop([])
    }
  }
  const { images, nextPage } = process.result
  if (nextPage) {
    return next(images, nextPage)
  } else {
    return stop(images)
  }
}

// inside scraper
return unfold(undefined, iterate)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, adding new providers is simple. It requires no duplication of control flow and not even a class. All that’s needed is some object that satisfies an interface. Notice how even with a function like &lt;code&gt;onError&lt;/code&gt;, we are simply taking a response as input and returning &lt;/p&gt;&lt;div&gt;a decision&lt;/div&gt; as a response, not performing an action. This framework allows the gears of &lt;code&gt;Scraper&lt;/code&gt; and &lt;code&gt;Provider&lt;/code&gt; to turn together without stepping over each other’s toes. Providers only know how to go, and scrapers only know how to tell providers to go.&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface Provider {
  process(url: string, pagination?: Pagination): Promise&amp;lt;ProviderResult&amp;gt;
  onError(response: Response): Promise&amp;lt;ErrorHandle&amp;gt;
  // any other functionality that could be customizable per site
}
&lt;/code&gt;&lt;/pre&gt;&lt;div my=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;I’ve skipped over how further implementation details of providers, persistence, publishing data, and other shenanigans work in Jiu in the interest of not boring people to death. But hopefully, this helps get a basic overview of implementing a generic scraper and decoupling business logic.&lt;/p&gt;&lt;p&gt;There are a couple more intriguing things I’ve come across while working on Kiyomi that I want to write about, like perceptual hashing and face recognition, but those will have to wait until I actually have any idea what I’m doing with them.&lt;/p&gt;&lt;p&gt;Here’s &lt;/p&gt;&lt;div href=&quot;https://github.com/Xetera/jiu&quot; target=&quot;_blank&quot;&gt;Jiu&lt;/div&gt; if you’re interested, and &lt;div href=&quot;https://kiyomi.io&quot; target=&quot;_blank&quot;&gt;Kiyomi&lt;/div&gt;.&lt;p&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🐿 Golang is not a good language]]></title><link>https://xetera.dev/thoughts-on-go/</link><guid isPermaLink="false">https://xetera.dev/thoughts-on-go/</guid><pubDate>Sun, 17 Oct 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/thoughts-on-go/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:802px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/83befa1d9e03f352fe0ba0f869c73d45/4a8d4/golang.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:47.599999999999994%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHUspMAX//EABgQAAMBAQAAAAAAAAAAAAAAAAEQERMh/9oACAEBAAEFAqdDVOr/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPwEJ/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFxAAAwEAAAAAAAAAAAAAAAAAACAxgf/aAAgBAQAGPwLSL//EABkQAAMBAQEAAAAAAAAAAAAAAAABESEQMf/aAAgBAQABPyHw1hkeUKzSNRXv/9oADAMBAAIAAwAAABCwz//EABcRAAMBAAAAAAAAAAAAAAAAAAEQIUH/2gAIAQMBAT8QNbq//8QAFhEBAQEAAAAAAAAAAAAAAAAAARAx/9oACAECAQE/EFyf/8QAHBAAAgICAwAAAAAAAAAAAAAAAREAIRAxQWGh/9oACAEBAAE/EEaqifcHApyXDISCKsT1Irz/AP/Z&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/83befa1d9e03f352fe0ba0f869c73d45/490da/golang.webp 250w,/static/83befa1d9e03f352fe0ba0f869c73d45/e333e/golang.webp 500w,/static/83befa1d9e03f352fe0ba0f869c73d45/9ba27/golang.webp 802w&quot; sizes=&quot;(max-width: 802px) 100vw, 802px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/83befa1d9e03f352fe0ba0f869c73d45/0479a/golang.jpg 250w,/static/83befa1d9e03f352fe0ba0f869c73d45/41099/golang.jpg 500w,/static/83befa1d9e03f352fe0ba0f869c73d45/4a8d4/golang.jpg 802w&quot; sizes=&quot;(max-width: 802px) 100vw, 802px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/83befa1d9e03f352fe0ba0f869c73d45/4a8d4/golang.jpg&quot; alt=&quot;golang&quot; title=&quot;golang&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;A month or two ago, I put an image of a tierlist of languages that I like using in my Github readme, ranked from F to S tier. F being my least favorite, and S being my favorite. It looked something like this:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/5f26e472d927f50d00db9a2be2167d61/38a65/language-preference.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:52%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAACHElEQVQoz32RzU+SARzHuXUpX3h4eB7o1WaIzmy+oAhMSyMoI2Hqk6gkolgCGmoJAmLOsrVmXWq2YevQ6tChtXnyVoe6d+gv6NCt4WatlfPTpDKz8vA5/C6f3/e7r2p1YhKSMzw530KfrZjZ7jEuu4cQCncjSxr0egmdTrvJxq2VRJyN5XR4HITDYUKhS4yMROjsVFBl52Os35vifqANx/E6hlv68J/qodRsochgQJZFdLo/pbIkYjx2iIrKUqzWeiyWOmw2CyZTNapPy0l4leL63ARHusfob7pA8PQAPbcfUetwIezZlUuVY2tKUYOoUaNW528iCAWosm/irL1N8TDuxWtuoq09gKvrIsq1aayKl/JmF/uLDqLbnlS/gfT72U9UK+/ifH0/zYurZ4kZj+LyD+EcT6Kkr3AyEqUhlGZfsQFRyEMrizm21t+O6vPHBHxLsPQgxg1PnDtBO6neZky9Ufp8dhYGD3PG56W+rZ8ZUw0eYwlqScPebWNtCj+splghxdNMjGjHFPNeE0mllqqeUfw+B4vDZbQE/Fi7IkxXV+L+JdT9R7i8Msrr9VEimTBlrgGC9kpCrgY8k7dwT9ykI32XxqEkNUoAURZz7Fg5k33G47XnDC7OYfONYa820FxlxNzaSa3zHJZWhYomJ6XWE7lh9DvIcsLYF0gAwaWXtI/PcqDEiFooQCvk/xhCyEPS5COLhX8t+i++A4VfZSD18eVlAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/5f26e472d927f50d00db9a2be2167d61/490da/language-preference.webp 250w,/static/5f26e472d927f50d00db9a2be2167d61/e333e/language-preference.webp 500w,/static/5f26e472d927f50d00db9a2be2167d61/54609/language-preference.webp 1000w,/static/5f26e472d927f50d00db9a2be2167d61/22285/language-preference.webp 1075w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/5f26e472d927f50d00db9a2be2167d61/63868/language-preference.png 250w,/static/5f26e472d927f50d00db9a2be2167d61/0b533/language-preference.png 500w,/static/5f26e472d927f50d00db9a2be2167d61/00d43/language-preference.png 1000w,/static/5f26e472d927f50d00db9a2be2167d61/38a65/language-preference.png 1075w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/5f26e472d927f50d00db9a2be2167d61/00d43/language-preference.png&quot; alt=&quot;language preference chart&quot; title=&quot;language preference chart&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;(S)&lt;/strong&gt; Rust, Haskell&lt;/li&gt;&lt;li&gt;&lt;strong&gt;(A)&lt;/strong&gt; Kotlin, Elixir, F#&lt;/li&gt;&lt;li&gt;&lt;strong&gt;(B)&lt;/strong&gt; Scala, Typescript, Dart, C#&lt;/li&gt;&lt;li&gt;&lt;strong&gt;(C)&lt;/strong&gt; Java, Ocaml, Python, Javascript, C++, Ruby&lt;/li&gt;&lt;li&gt;&lt;strong&gt;(D)&lt;/strong&gt; PHP, Coffeescript, Powershell, Lua, Clojure&lt;/li&gt;&lt;li&gt;&lt;strong&gt;(F)&lt;/strong&gt; Go&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;p&gt;Part of me obviously just wanted to put that up to get reactions out of people. It’s a little bit nonsensical to try to rank programming languages in a tierlist. I’m not sure what you’d have to be looking for to compare a language like Dart with Powershell.&lt;/p&gt;&lt;p&gt;I had opinions on a few more languages, but the tierlist I was using didn’t have them. Maybe I’ll make my own website for ranking programming languages at some point.&lt;/p&gt;&lt;p&gt;Anyways, plenty of people were upset over how I placed their favorite languages in the C tier. Some people were surprised to see their choice, like Haskell and F# at the top. But &lt;/p&gt;&lt;div text=&quot;Gophers&quot; color=&quot;blue.300&quot;&gt;Name given to the people in the Go community&lt;/div&gt; were &lt;div&gt;FURIOUS&lt;/div&gt; that their favorite language was the only one at F tier and demanded an explanation from me, pressing a metaphorical knife to my throat.&lt;p&gt;&lt;/p&gt;&lt;p&gt;So let me explain what I have against Go. Also, just as a disclaimer, I don’t like hating on languages &lt;/p&gt;&lt;div&gt;too much&lt;/div&gt;. Most of them just want to be tools and have their own shortcomings. But a lot of problems Go experiences seem to be self-imposed restrictions through an ideology that wilfully ignores decades of important language research, which just doesn’t make sense to me.&lt;p&gt;&lt;/p&gt;&lt;h2 id=&quot;correctness&quot;&gt;&lt;a href=&quot;https://xetera.dev/#correctness&quot;&gt;Correctness&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I don’t know about everyone else, but I am a pretty bad programmer. I often make silly mistakes in my code or skip important things in code review that I should be catching. I’m confident in my skills, but if you were to put a gun to my head and tell me my code has to work as intended in my first attempt to save my life, the last memory flashing before my eyes would be something like:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;TypeError: cannot read &quot;name&quot; of undefined
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:713px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/1836bc5c5a8383828ca9496e3ac3bccb/01267/tar.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:32%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAABWUlEQVQY0yXHsc7BUBgA0L6GmKyd/kEXCWGQRlIJNg9g8AImsYlcHUUiBoNBQyMRL9BFiDuIqSTapsMtReoOrdRNyifxn+1wq9XKNM3z+RyGoWEY+Xw+l8ul0+lMJlMsFm3bZoz5vv96va7XKyHEdd0gCBhjhBDONM3L5eK6LgA4jiOKYjabrVQqkiRVq9X7/Q4A7/cbAHzfd37+63keRykNguB4PFqWdTqdkslkPB5PpVKxWEwQBM/zACCKos/nQym93W5hGFqWpev64XDgttutrutRFAHA4/FotVqNRqPZbE4mk+l0ut/vbduGn+fziTE2DIMxBgCUUm4+n6uqihDqdDqLxUJRlOVyORgMer2eqqqz2Ww0GsmyjBAaDofj8VhRlH6/3263EUIcIUTTtL+fbreraRrGuFAoJBKJer2+2WzW67UoijzP12o1jPFutyuVSjzPl8vlL1mx+jal+yqJAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/1836bc5c5a8383828ca9496e3ac3bccb/490da/tar.webp 250w,/static/1836bc5c5a8383828ca9496e3ac3bccb/e333e/tar.webp 500w,/static/1836bc5c5a8383828ca9496e3ac3bccb/4154e/tar.webp 713w&quot; sizes=&quot;(max-width: 713px) 100vw, 713px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/1836bc5c5a8383828ca9496e3ac3bccb/63868/tar.png 250w,/static/1836bc5c5a8383828ca9496e3ac3bccb/0b533/tar.png 500w,/static/1836bc5c5a8383828ca9496e3ac3bccb/01267/tar.png 713w&quot; sizes=&quot;(max-width: 713px) 100vw, 713px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/1836bc5c5a8383828ca9496e3ac3bccb/01267/tar.png&quot; alt=&quot;untar xkcd&quot; title=&quot;untar xkcd&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;I want a compiler to have my back. We humans suck when it comes to keeping complex conditions and details in our heads, but computers are basically designed to be good at that. I want a computer to tell me when I’m making a mistake at the time of writing the code. Hell, I wish the computer could just write the code for me to begin with. At the end of the day, I just don’t want to hope that every single person I’m working with is just a God developer who can catch every mistake before changes are pushed to production because that just doesn’t ever happen.&lt;/p&gt;&lt;div borderradius=&quot;md&quot; as=&quot;video&quot; width=&quot;100%&quot; src=&quot;static/null_pointer-abce8abf9ed414635ce2b69150d2d032.mp4&quot; playsinline=&quot;&quot; controls=&quot;&quot; mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;Golang claims to be a proponent of this concept too, and it shows that by enforcing one of the most annoying linter warnings of all time in the form of an error directly inside the compiler. The one where it prevents your program from compiling if you have an unused variable anywhere in your code.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:758px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/4434d7d83b03109643df529b8962c63c/c8e86/unused_variable.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:59.199999999999996%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB0UlEQVQoz2WRS47UMBCGcxA2CJCI33bZLr+6k3Sc0N3MjEaDZsuKC7BAsIELsODKyEmPhMQnq2z9UtVf5eqcczlnjxhjSinHmEop7R0ThpBzyRsp5ZxLCLGUgzGGMcY570KMtS7jONZlmec6DOM812VZx2lKOde6LMtaymHLT6304SilpJS2ZCGEUso5Z611zgFYA4De74rfUFpLIVVDSim11gAghOgArPc4TdN0Oh2HARG9c977GGMIAT16xJRSwBBjRAwYAm6KlLLzGEKMpZTD4ZhztnbvwAOA29j9b6K1rTCi1pox1hkDMeXr9ePler27u79/eLhcrrUup3met4kb67qsy+V8qU1Zz+fLXKvRupNKGYBStl/dYgjBGAMAxoDWiv4HIeT221IqbYxHbG21eR0ihm0wxGCd5aLB+X7f4E0RHWesWftESE8poZSyG5SRnlHCGeG8+XDac/J+P4L2gtGOcy6FtM7BbVXAN4RQwiUGgdnMlGGM0+Gezs/9+NQPj2/KYw+l2/vRWm9rbLF5UGo9Pn3+EqbVHavH0DP99fevD9/+vH7++e7T91ePP97mu273Yf/w4izAWq2EklwpyYWM46BKJTgSnHo8Ee3/AnjcmO6ESs14AAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/4434d7d83b03109643df529b8962c63c/490da/unused_variable.webp 250w,/static/4434d7d83b03109643df529b8962c63c/e333e/unused_variable.webp 500w,/static/4434d7d83b03109643df529b8962c63c/676c3/unused_variable.webp 758w&quot; sizes=&quot;(max-width: 758px) 100vw, 758px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/4434d7d83b03109643df529b8962c63c/63868/unused_variable.png 250w,/static/4434d7d83b03109643df529b8962c63c/0b533/unused_variable.png 500w,/static/4434d7d83b03109643df529b8962c63c/c8e86/unused_variable.png 758w&quot; sizes=&quot;(max-width: 758px) 100vw, 758px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/4434d7d83b03109643df529b8962c63c/c8e86/unused_variable.png&quot; alt=&quot;unused variable&quot; title=&quot;unused variable&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;After all, if you have unused variables, chances are you might have done something wrong. It doesn’t make a whole lot of sense to declare a variable and not use it. This is a perfectly reasonable argument to make.&lt;/p&gt;&lt;p&gt;Unfortunately, if you’re used to commenting things out when developing, this is going to force you to jump through a bunch of hoops and have somewhat of a clown moment in your codebase just to test stuff out.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:745px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/367443052c090152a14469b4424a5e3b/7e509/unused_variable_solution.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:100%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsTAAALEwEAmpwYAAACRUlEQVQ4y41UiZKjIBT0MyZROcRbUCdRQSDeJrP7/x+0hWZTmdmZrbRd1ANfV3M+K8/zoizbtuVCiNaAc8G5UEpJKUVrxoQQXPC2bZXSUkqllBCCMWbVDW+Vnud5GMZ5XuZ5HsdxmubFYB2naV3XdVmmcRyGYZymYRyHcTydTkbcNEIp3fd9PwzjltEPQ7/1N/bjvOhh1sNyrnlR5OwJVnk+VW1TVVXVNK0QdV1zzptmG6mquq5OjUgqHddd2ciiyNMNWZZRSq335py/5x4JgzAOCbEPb/bh8EzneACGb87x4ByPrm27tu0cjwRjq8gLmlGfBHEUIAAC4vue53sewZhg7CG0ZTsb7QfvYsZYlmUYIQIdgiB0XOA4z3zWfC/2sJcFJPYJhtB4IuNJMNrz/qV9OHi7mFIaEIIR9jAmnvcKPYzDMLQopWVZdl3Hm5oxmr8Oxu7TDsIoiuI4iiAAEAAEAILwP4QABL5vsZxlaer7URRHZsWuiyFEAPy02q9rNrsNEQIOdJ2H+Kd9/m63PcJCPw0DBOHD+VUxsB0EAHRd17b34/1yzz7dOdO+3afNKM2SJInjJN7bOEmSNDVDSRynSfLMHWFkMi1GafF+1svvy+WitVZKa6Uv5ruYh6uUiS5d13V6g1JaqC7nXc7yzTkvWHkyd4X9bdg+Ico+YzvdLWDml7V3pJTr9Xr7+LWs12VZr7eP6+1jvd5McL1NpkKY+rBVi3VZ1qqqzZPcxc29CEm+1yJpAill20oh2s3K+O7mD/8/7i3HSovhUfgAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/367443052c090152a14469b4424a5e3b/490da/unused_variable_solution.webp 250w,/static/367443052c090152a14469b4424a5e3b/e333e/unused_variable_solution.webp 500w,/static/367443052c090152a14469b4424a5e3b/ff36f/unused_variable_solution.webp 745w&quot; sizes=&quot;(max-width: 745px) 100vw, 745px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/367443052c090152a14469b4424a5e3b/63868/unused_variable_solution.png 250w,/static/367443052c090152a14469b4424a5e3b/0b533/unused_variable_solution.png 500w,/static/367443052c090152a14469b4424a5e3b/7e509/unused_variable_solution.png 745w&quot; sizes=&quot;(max-width: 745px) 100vw, 745px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/367443052c090152a14469b4424a5e3b/7e509/unused_variable_solution.png&quot; alt=&quot;unused variable solution&quot; title=&quot;unused variable solution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Aside from being &lt;/p&gt;&lt;div&gt;unbelievably annoying&lt;/div&gt;, I think workarounds like these arguably become a bigger vector for bugs in your code than leaving things unused or having linter warnings. Once you’ve decided to go down the workaround route, you’ve decided to add a hack into your code to solve this issue, but are still implicitly relying on the compiler to let you know when things are unused. When you make changes later on, and that variable turns from a simple unused variable into a legitimate bug, you feel confident in the correctness of a program that is no longer being enforced by anything in that specific instance.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Overall, I actually think this is an understandable check to have in a language that is truly concerned with correctness. If your language believes it should be as difficult as possible for a developer to add bugs in their programs, making life difficult in ways that feel unnecessary is just one of the Ls that developers have to take for extra safety. Even when that involves the language making controversial decisions or disrupting devs development cycles.&lt;/p&gt;&lt;p&gt;The only problem is, Go doesn’t seem to be interested in safety or correctness at all. It wholeheartedly embraces null pointer exceptions —which tends to be by far the most common source of bugs in languages that implement it— by creating an error handling system where dynamic values can be null at any time with no compiler checks involved. You simply have to remember not to create bugs and to check errors before dealing with error-able values. Quite a different philosophy from the one Go’s unused variable check would like to have you believe it adopts.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:680px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/3e7100eac2ee925282647783230f6416/7bf67/type_safety.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:100%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAQBAgP/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgD/2gAMAwEAAhADEAAAAecp8yuGDVTlTGMf/8QAHBAAAgICAwAAAAAAAAAAAAAAAQIAEgMhMTJB/9oACAEBAAEFAns5x9mG/QoU3EMYw8//xAAXEQADAQAAAAAAAAAAAAAAAAAAEBEh/9oACAEDAQE/AYY//8QAFhEBAQEAAAAAAAAAAAAAAAAAEAER/9oACAECAQE/AdKf/8QAHRAAAQIHAAAAAAAAAAAAAAAAAAERAhIgITFRYf/aAAgBAQAGPwKWBMCupYbZ2n//xAAcEAACAwADAQAAAAAAAAAAAAAAEQEhMUFRYZH/2gAIAQEAAT8hshfXz0NPymQeA1NE1DS7MltOSDo2ND//2gAMAwEAAgADAAAAEJD4Qf/EABkRAAIDAQAAAAAAAAAAAAAAAAABETFBUf/aAAgBAwEBPxB6J6EOz//EABgRAQEAAwAAAAAAAAAAAAAAAAEAEBFB/9oACAECAQE/EDhjeBf/xAAcEAEBAAMBAAMAAAAAAAAAAAABEQAhMVFBYfD/2gAIAQEAAT8QoQIuoVoxN0IjZT3IBcBftxuUKLp7+MQgoJvE9ytAnyGsAK2E7vElAoPV8xcNF4Z//9k=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/3e7100eac2ee925282647783230f6416/490da/type_safety.webp 250w,/static/3e7100eac2ee925282647783230f6416/e333e/type_safety.webp 500w,/static/3e7100eac2ee925282647783230f6416/a825c/type_safety.webp 680w&quot; sizes=&quot;(max-width: 680px) 100vw, 680px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/3e7100eac2ee925282647783230f6416/0479a/type_safety.jpg 250w,/static/3e7100eac2ee925282647783230f6416/41099/type_safety.jpg 500w,/static/3e7100eac2ee925282647783230f6416/7bf67/type_safety.jpg 680w&quot; sizes=&quot;(max-width: 680px) 100vw, 680px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/3e7100eac2ee925282647783230f6416/7bf67/type_safety.jpg&quot; alt=&quot;type safety&quot; title=&quot;type safety&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Claiming to care about safety through questionable checks and not addressing &lt;/p&gt;&lt;div&gt;null pointers&lt;/div&gt; is kind of like if a city tried to combat crime by enacting a curfew after 8pm. Certainly a valiant effort that will help maybe… a little bit? But it makes everyone’s lives significantly harder and doesn’t do anything to address the obvious issue at hand.&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func thing() {
  result, err := doThing()
  // is result nil or defined? Dunno but hope you don&apos;t forget to check
  print(result.someField)
  // runtime error:
  // panic: invalid memory address or nil pointer dereference
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is in contrast to a language like Rust, which won’t let you shoot yourself in the foot with any value that may be an error or undefined.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn thing() {
  let result = do_thing();
  println!(result.some_field);
  // compile-time error:
  // error[E0609]: no field `some_field` on type `Option&amp;lt;Thing&amp;gt;`
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Not to mention, for the amount of emphasis being put on concurrency, Go also doesn’t address the inherent problems that come with it other than by the design of the language itself (channels as a means of communication between goroutines and such). It has some checks in place to make sure that things like data races are unlikely, but doesn’t actually go out of its way like Rust to make sure they’re not possible. Safety seems to get sidelined in favor of things like easy adoptability. You don’t need your compiler to prevent the programmer from adding bugs if the programmer just doesn’t add them in the first place, right?&lt;/p&gt;&lt;p&gt;The lack of these kinds of features isn’t always a problem for me. Safety and static typing are really important, but not necessarily a dealbreaker for my taste. I like Elixir enough to put it in A tier (whatever that means at this point) which is a dynamically typed language, mind you. And much like Go, Elixir also does not concern itself with preventing the user from adding bugs in their code too much. But the difference is, unlike Go, Elixir embraces the fact that it can’t ensure there will never be problems. It doesn’t pretend to care about correctness to the point of adding ridiculous compiler checks in ways that don’t add any safety. Instead, it has built-in mechanisms to recover from failure as intelligently as possible as a part of the language, and decides to incorporate failure into the way problems are solved in that paradigm.&lt;/p&gt;&lt;p&gt;Of course, caring about safety in a language isn’t just a binary choice of “this language is safe” and “this language isn’t”. It’s just that Go’s priorities when it comes to correctness and safety seem very misguided. Most of its safety features are implemented in the form of radically opinionated language choices that make people upset like &lt;a href=&quot;https://nathanleclaire.com/blog/2014/04/27/a-surprising-feature-of-golang-that-colored-me-impressed/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;intentionally undeterministic map iteration&lt;/a&gt; or the lack of &lt;a href=&quot;https://blog.merovius.de/2018/06/03/why-doesnt-go-have-variance-in.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;support for variance in its type system&lt;/a&gt;. Decisions that make a good-faith effort in trying to prevent the user from firing a bullet at their feet with a gun that does a concerningly good job shooting at feet by design.&lt;/p&gt;&lt;h2 id=&quot;simplicity&quot;&gt;&lt;a href=&quot;https://xetera.dev/#simplicity&quot;&gt;Simplicity&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The reasoning behind this archaic error checking method and the unused variable thing is that Go wants to be as simple as possible. One way to ensure that simplicity is by only allowing a single “Go way” of doing things. Every engineer working on a shared codebase should be able to hit a problem with a Go-shaped hammer and get a predictable Go-shaped solution out of it. If you’re not allowed to handle errors in any way other than always explicitly passing it back to the caller, for example, there’s no debate to be had about how error handling should be done. Except for when there &lt;a href=&quot;https://github.com/golang/go/issues/32437&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;is a debate&lt;/a&gt;, of course.&lt;/p&gt;&lt;p&gt;Go’s philosophy seems to hint that complexity only comes in the form of complex abstractions. That if you are not given complex tools like union types, generics, or macros, your programs will necessarily be simpler. And this to me seems like a child’s way of thinking about how complexity arises in programs. Simplicity does not exist on a linear scale of &lt;/p&gt;&lt;div&gt;complicated&lt;/div&gt; and &lt;div&gt;not complicated&lt;/div&gt; languages. It’s a delicate balance across many things in multiple dimensions. Sure, having too many tools and too many ways of doing the same thing is going to cause complexity like it does with a language like C++, but so will having no tools to deal with complex issues. After all, you can’t be expected to chop down a tree with a steak knife. When your go-to abstraction for generalizing solutions is copy paste, that extra effort you had to spend learning and understanding new abstractions is now going to be used to maintain code written with a steak knife; making understanding a solution built with simple ideas much more difficult than it has to be.&lt;p&gt;&lt;/p&gt;&lt;p&gt;You’d much rather have access to more complex concepts to represent more complex problems in those situations, because complexity isn’t inherently bad. Maybe you don’t want to have to understand what the hell a &lt;/p&gt;&lt;div&gt;Semigroup&lt;/div&gt; is to add 2 lists together, but you also don’t want to have to copy paste this meme&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; metastring=&quot;{lines:true}&quot;&gt;if err != nil {
  return nil, err
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;13 times in the same function and then copy paste that function N times for all data types only to solve an otherwise-trivial problem.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; metastring=&quot;{lines: true, title: &amp;quot;net/protoconn_test.go&amp;quot;}&quot;&gt;if _, _, err := c1.WriteMsgUnix(wb, nil, a2); err != nil {
  t.Fatal(err)
}
if _, _, _, _, err := c2.ReadMsgUnix(rb2, nil); err != nil {
  t.Fatal(err)
}
if _, err := c2.WriteToUnix(wb, a1); err != nil {
  t.Fatal(err)
}
if _, _, err := c1.ReadFromUnix(rb1); err != nil {
  t.Fatal(err)
}
if _, err := c3.WriteToUnix(wb, a1); err != nil {
  t.Fatal(err)
}
if _, _, err := c1.ReadFromUnix(rb1); err != nil {
  t.Fatal(err)
}
if _, err := c2.WriteToUnix(wb, a3); err != nil {
  t.Fatal(err)
}
if _, _, err := c3.ReadFromUnix(rb3); err != nil {
  t.Fatal(err)
}
&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;Fun little example from Golang&apos;s own standard library. Sure, it&apos;s a test file, but I think that only proves my point of needing situational complexity even more.&lt;/div&gt;&lt;p&gt;This idea of simplicity-gone-too-far appears in many places. Go makes extensive use of “tuples” when returning 2 or more values from functions, but tuples don’t actually exist in the language. It uses a keyword &lt;code&gt;range&lt;/code&gt; to iterate over maps and arrays, but has no concept of an iterable data type. Plenty of features are implemented in the form of very specific compiler magic, and the only explanation for it is that it’s to prevent you from building your own abstractions. If a language is opinionated in not adding complex abstractions, allowing the user to build their own would kind of defeat the whole idea.&lt;/p&gt;&lt;h2 id=&quot;community&quot;&gt;&lt;a href=&quot;https://xetera.dev/#community&quot;&gt;Community&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Simplicity on its own is not necessarily a bad thing to strive for, even when done well. But the way Go approaches it is a little… well, I’ll just let you decide how you feel about &lt;a href=&quot;https://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/From-Parallel-to-Concurrent&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;this quote from Rob Pike&lt;/a&gt;, one of the creators of the language.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div messages=&quot;[object Object],[object Object],[object Object]&quot; date=&quot;May 19, 2014&quot; username=&quot;Rob Pike&quot; rolecolor=&quot;orange.500&quot; avatar=&quot;[object Object]&quot; reactions=&quot;[object Object],[object Object]&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;I find it really funny how he&apos;s talking about devs at Google (a position that many developers can only dream of having) as being too inexperienced to handle a good language.&lt;/div&gt;&lt;p&gt;Go doesn’t only want to make your life easier by preventing arguments about menial things. Its philosophy is based on the idea that you’re incapable of dealing with the tools you think you should have. Why don’t we have generics in the language? Because generics are hard and you just graduated from college last year. Copy and paste it instead.&lt;/p&gt;&lt;p&gt;Maybe I’m just being weird here but I don’t really want to use a language built by people who think they’re better than me…? Like, don’t get me wrong, almost everyone working on Go certainly is. I just don’t think this is a healthy way of building a relationship with a community, though this might also be the brash nature of Rob Pike in specific.&lt;/p&gt;&lt;p&gt;This seems to be an issue that shows up in the Go community fairly often. If you look at discussions of problems and proposals like &lt;a href=&quot;https://github.com/golang/go/issues/32825&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;proposal: leave &lt;code&gt;if err != nil&lt;/code&gt; alone? #32825&lt;/a&gt;, they tend to have a predictable format across the board. In one corner we usually have the “please sir I just want to use a good language” team, asking for changes that they feel are going to make their lives easier. And in the other corner, we have the “you just don’t understand the language man” team, trying to convince the users that they don’t actually want the things that they want; alienating the userbase with a mix of patronization or stockholm-syndrome depending on where it’s coming from.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:508px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/1d157beccbf2291024dffbf99b3f73b2/2fd48/actually_youre_wrong.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:32.4%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAvklEQVQY04WPW4qFQAxEXU8/1G7tvJMGcf9rGrx+DcNlDhQpQlIkS+udiFQVAHLOOaWc3/rwmo9+d3KutS7rtq3r2o+DiRBRzUWUmSNCVUUkIkQeY+5mpqruTsz7vi+ApBbnOUyViMzsHXV/UoiImRGRCJmZRZhYmAHwWR6AiAhjxJwiombMPOd0jzln7y2lVErJfyilLAAo6q319x4RmXPCGLXW7fNR/c7S+3EOaK2LynVdHnHfN4xRSqn/8QMunUiObyIIUwAAAABJRU5ErkJggg==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/1d157beccbf2291024dffbf99b3f73b2/490da/actually_youre_wrong.webp 250w,/static/1d157beccbf2291024dffbf99b3f73b2/e333e/actually_youre_wrong.webp 500w,/static/1d157beccbf2291024dffbf99b3f73b2/cef30/actually_youre_wrong.webp 508w&quot; sizes=&quot;(max-width: 508px) 100vw, 508px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/1d157beccbf2291024dffbf99b3f73b2/63868/actually_youre_wrong.png 250w,/static/1d157beccbf2291024dffbf99b3f73b2/0b533/actually_youre_wrong.png 500w,/static/1d157beccbf2291024dffbf99b3f73b2/2fd48/actually_youre_wrong.png 508w&quot; sizes=&quot;(max-width: 508px) 100vw, 508px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/1d157beccbf2291024dffbf99b3f73b2/2fd48/actually_youre_wrong.png&quot; alt=&quot;actually youre wrong&quot; title=&quot;actually youre wrong&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;div&gt;&quot;Have you considered not having a problem with this?&quot;&lt;/div&gt;&lt;p&gt;It seems like this divide exists because Go was never built for a community in the first place; it was built for Googlers. It only ended up taking off with the rest of the programming community due to being open source and its amazing approach to concurrency, which was the main problem they were trying to solve at the time. But because it was never built for a community, it has all of this baggage that makes sense in the context of a company imposing restrictions on its employees with what they believe to be the correct approach, but not with a language open for everyone to use.&lt;/p&gt;&lt;p&gt;It took the language maintainers a ton of pushback from the community on their puritanical ideals about what they think the perfect language should be like to create a language that the people actually enjoy using. Sadly, they’ve tucked all of that away in the promise of a Go 2 that’s still yet to come.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;There are some honorable mentions that I didn’t include here like Go’s &lt;/p&gt;&lt;div&gt;hilariously bad&lt;/div&gt; approach to date formatting.&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:766px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/a09d234e3692f42f7d12ad4df7e8ae3f/f7616/date_formatting.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:111.6%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAWCAIAAABPIytRAAAACXBIWXMAAAsTAAALEwEAmpwYAAACq0lEQVQ4y42UyY7cNhBA9RlOZsZxL+qWWMVV4k6pF6k9PTMe+JBDTgHyD7nkknOST8lfBpQ6Y487DvzwIBASSFaxSiyc8/f35/3hMJ5O43g6DsNxHPPgOJxO98M4DMN4Pj88PX14eHx6P3EchnE8nR8eCqWU896HTEqpbbX33lqrjZnfcs4455RS/hohRMGFkEo555x3PnjnLguFEEMI3vuUuuNx6Hc7zjn7DEQsjLFaGyBECqGkBELqqqqriuRBXdcVRcooo0g3ZVmu1y8iQKG1UarZlqXkXDCGAJv1Yrv5oa7elat3b29vb757M3t38/3dzc3s29tbQkghpFRN07ZtMz3pF+DkPHwNpTTnzDlXUnnnrDFfxPY/5pw554hYVxWjFAFWy8Vy8U0CQIGIQogQQtd1wXs2Rcj+k6loWZbNYVNExoXrB78b3W4Mx7Pt9nNKr5NHjoRCTaFmQBgQirTI+3DeGjdpW2O5UPQKZLxsEtgd2j2xu23bIRPFHKScUEpJKeinbVmWMQDSuu6Pv/5mv/y5/un35Y+/3T3/WitXvJQBAAiBGQRAvEinL5zL548/Y/9cdY91etrGR+DqMlkIkWLsUur7Xd93MXYu9i71od/b2LuQXEiqbYJ33hlntW4VRSzmwxWNCf0hpD7FlGI0oRNhkPGg0iDDUZrY2GitM9ZpY5VqpMznUkzNwqnuUPfAOAD5FHmW4L9ZvDDlSC5NIpXiSjPZvlT01YF9Rm7HSa2NVKpomuaw38cY6HVtrzDWGuus8+/Pj6nb5d5WTQamyXPLI1686rELjOeIinkxIDk3UtdTXSogJZANqTfr1Wq1WKyWy2tzb7fatK0mVc3yVjBVnFCsESqEervZluvy639VKxtvnLF+usOm+ydOV1FMMdrYU/3V4/gHGFL4jsc2YwkAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/a09d234e3692f42f7d12ad4df7e8ae3f/490da/date_formatting.webp 250w,/static/a09d234e3692f42f7d12ad4df7e8ae3f/e333e/date_formatting.webp 500w,/static/a09d234e3692f42f7d12ad4df7e8ae3f/12f3f/date_formatting.webp 766w&quot; sizes=&quot;(max-width: 766px) 100vw, 766px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/a09d234e3692f42f7d12ad4df7e8ae3f/63868/date_formatting.png 250w,/static/a09d234e3692f42f7d12ad4df7e8ae3f/0b533/date_formatting.png 500w,/static/a09d234e3692f42f7d12ad4df7e8ae3f/f7616/date_formatting.png 766w&quot; sizes=&quot;(max-width: 766px) 100vw, 766px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/a09d234e3692f42f7d12ad4df7e8ae3f/f7616/date_formatting.png&quot; alt=&quot;date formatting&quot; title=&quot;date formatting&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;and a couple others, but I didn’t think they deserve the same criticism because they’re just weird corners of the language and don’t make as much of an impact on the overall experience.&lt;/p&gt;&lt;p&gt;Overall, Go is not built by inexperienced people or anything, or even a bad language depending on what you value. It makes a lot of opinionated choices and deliberate compromises of important ideas to solve problems that I just don’t consider to be worthwhile at all and sometimes even harmful. Go has not learned anything from decades of programming language research and re-implements all the same problems that language designers have &lt;a href=&quot;https://hackernoon.com/null-the-billion-dollar-mistake-8t5z32d6&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;expressed endless regret over&lt;/a&gt;. The concurrency is awesome, but the pain of actually using the rest of the language simply isn’t worth it.&lt;/p&gt;&lt;p&gt;Just use Rust instead.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🔑 Building a robust permissions system in TypeScript]]></title><link>https://xetera.dev/typescript-permissions/</link><guid isPermaLink="false">https://xetera.dev/typescript-permissions/</guid><pubDate>Sun, 05 Sep 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/typescript-permissions/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Have you ever tried to deal with permissions in your app and run into this issue?&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;function onSubmit() {
  if (!user.hasPermission(Permission.WRITE_COMMENT)) {
    sendMessage({
      message: &quot;Sorry you can&apos;t post comments!&quot;,
    })
  }
  submitComment(user, form.comment)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;AGH! You just forgot to return early from the permission check and ended up trying to write a comment &lt;em&gt;anyways&lt;/em&gt;! If you made this mistake on the frontend, you probably got some annoying errors from a backend that hopefully didn’t make the same mistake you did. If you did it on the backend, you just introduced a pretty serious vulnerability in your app. Let’s hope this got caught in code review. Otherwise, you probably caught these hands instead.&lt;/p&gt;&lt;p&gt;How do we prevent this? A bug like this seems impossible to avoid other than by just being very careful; we would need TypeScript to read our minds here if we wanted it to prevent us from doing this, wouldn’t we? Err… well, no, but that might be a planned feature for an upcoming TypeScript update.&lt;/p&gt;&lt;p&gt;We’re making an assumption here, where we believe that all users passed into &lt;code&gt;writeComment&lt;/code&gt; are going to have the &lt;code&gt;WRITE_COMMENT&lt;/code&gt; permission. The problem is, we’re not telling the typechecker that there’s any difference between an authenticated user who can write comments and a user who’s logged out, so it can’t fail when we use an unauthorized user to do authorized stuff. We’re doing a check with an if statement to gain valuable information about the properties of the data we’re working with, but we’re not turning that information into something the typechecker can use to do its job; the type of &lt;code&gt;user&lt;/code&gt; stays the same despite our explicit check. It’s an anti-feature to use a single &lt;code&gt;User&lt;/code&gt; type when we’re working with two incompatible ideas, so why not try to come up with a better system that’s capable of representing the data we’re working with more accurately to make sure bugs like this can’t even compile.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;We’re going to start by defining our base &lt;code&gt;User&lt;/code&gt;, which will represent any user on the site who may or may not be authenticated.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;type User = {
  // this is the only relevant property for our system
  permissions: number
  // with any other user-related property
  // you can think of
  name: string
  age: number
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This specific example uses a bitfield to store the permissions a user can have, which is represented with &lt;code&gt;number&lt;/code&gt;. What you use for storing permissions internally is not important. Unless you’re working on the Discord API and want to provide your users a bad experience, you most likely won’t be directly exposing things like bitfields to the consumers of your API anyways. This concept works with any permission system.&lt;/p&gt;&lt;p&gt;Now, let’s define a new &lt;code&gt;AuthorizedUser&lt;/code&gt; type to declare a user who’s had a permission check, as we’re going to need a distinction between the two if we want to allow the typechecker to do work for us.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines: true}&quot;&gt;type AuthorizedUser&amp;lt;T extends Partial&amp;lt;Permissions&amp;gt;&amp;gt; = User
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Whoa hold up. Why is there a &lt;code&gt;T&lt;/code&gt; generic here if it’s not even being used? Shouldn’t you get rid of it?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This type parameter is known as a &lt;/p&gt;&lt;div&gt;Phantom Type&lt;/div&gt; in Haskell (and probably is a functional programming concept in general). Phantom types are parameters that are not a part of the type definition and are only used to differentiate one type from another based on some criteria to provide additional safety.&lt;p&gt;&lt;/p&gt;&lt;p&gt;The idea is that an &lt;code&gt;AuthorizedUser&amp;lt;T&amp;gt;&lt;/code&gt; should always be a valid &lt;code&gt;User&lt;/code&gt; but not the other way around. Authorized users are defined with &lt;code&gt;User&lt;/code&gt;, making them compatible (or easily convertible in the case of other languages). But &lt;code&gt;User&lt;/code&gt; is distinct from &lt;code&gt;AuthorizedUser&amp;lt;T&amp;gt;&lt;/code&gt;, so it cannot be used interchangeably with it. Phantom types help us fine-tune this subtyping relationship using the constraint of permissions.&lt;/p&gt;&lt;p&gt;Unfortunately for us, TypeScript does not care that &lt;code&gt;AuthorizedUser&lt;/code&gt; has a different name from &lt;code&gt;User&lt;/code&gt; because it uses a structural type system. The name you give a type is not taken into account by the typechecker when comparing two types, only the definition itself. If the fields of any two types match, TS considers those two to be compatible. So we’re actually forced to use &lt;code&gt;T&lt;/code&gt; in the definition in order to distinguish it from &lt;code&gt;User&lt;/code&gt;. You could argue this makes it not a phantom type anymore, but I could argue that you’re dumb and win the argument immediately.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true,h: 3}&quot;&gt;type AuthorizedUser&amp;lt;T extends Partial&amp;lt;Permissions&amp;gt;&amp;gt; = User &amp;amp; {
  // just here to make typescript happy
  __permission__: T
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will work, but we can accidentally access &lt;code&gt;__permission__&lt;/code&gt; even though it’s not meant to be used, because it won’t ever be assigned a value. We can use a &lt;/p&gt;&lt;div&gt;unique symbol&lt;/div&gt; to make sure it’s not accessible in our code by anything other than that symbol, which we will not be exposing to the rest of our codebase.&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{h: &amp;quot;1,4&amp;quot;, lines:true}&quot;&gt;declare const phantom: unique symbol
type AuthorizedUser&amp;lt;T extends Partial&amp;lt;Permissions&amp;gt;&amp;gt; = User &amp;amp; {
  // just here to make typescript happy
  [phantom]: T
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It’s worth noting that if you have any properties that should only exist for an authenticated user, you could declare them in this type. There’s even a way to make them only appear for a specific type of permission, but that’s a story for another day.&lt;/p&gt;&lt;p&gt;Now that we’ve declared users, it’s time to head over to the original &lt;code&gt;submitComment&lt;/code&gt; function definition.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines: true}&quot;&gt;async function submitComment(user: User, comment: Comment) {
  // your favorite commenting implementation here
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s change this function by baking the assumptions we’re making about the authorization level of &lt;code&gt;user&lt;/code&gt; in our mind directly into the type signature.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines: true, h: 2}&quot;&gt;async function submitComment(
  user: AuthorizedUser&amp;lt;WriteComment&amp;gt;,
  comment: Comment
) {
  // exact same code as above
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Remember, nothing changes with the implementation of this function when we change the user type, since an &lt;code&gt;AuthorizedUser&amp;lt;T&amp;gt;&lt;/code&gt; is a valid supertype of &lt;code&gt;User&lt;/code&gt;. The responsibility of disambiguating between these types is on the consumer, not the provider. As far as we’re concerned inside &lt;code&gt;submitComment&lt;/code&gt;, we’re still working with a regular &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;&lt;div title=&quot;Fun side-note&quot; mb=&quot;6&quot;&gt;If you&apos;re working in a team, using a declarative approach like this also makes the capabilities of this function and your intentions crystal clear to your coworkers. What is a restriction for typecheckers is often documentation for humans. 😊&lt;/div&gt;&lt;p&gt;Let’s take a look at the implementation of &lt;code&gt;Permissions&lt;/code&gt; and &lt;code&gt;WriteComment&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;const writeComment = { writeComment: true } as const
type WriteComment = typeof writeComment

const readComment = { readComment: true } as const
type ReadComment = typeof readComment
type Permissions = WriteComment &amp;amp; ReadComment // &amp;amp; anything else
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Huh, this seems like a strange way to do permissions, why not use an &lt;/p&gt;&lt;div&gt;enum&lt;/div&gt; the way God intended?&lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Using enums is certainly clearer and easier to read, but it comes with a pretty severe limitation that makes it unusable for our purpose. Consider the following code:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;enum Perm {
  WriteComment,
  ReadComment,
  BanUser,
}

function renderCommentsSection(
  user: AuthorizedUser&amp;lt;Perm.WriteComment | Perm.ReadComment&amp;gt;
) {
  // implementation here
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For this component to be rendered on your app, the user would need to be able to either write comments OR read them. If they can’t do either then there’s no component to even display. Nothing particularly wrong about this case. Enums are just numbers or strings at the end of the day, and this is something that you can easily represent with an enum; it’s just &lt;code&gt;0 | 1&lt;/code&gt;. But what about this case?&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function renderCommentsModerationPanel(
  user: AuthorizedUser&amp;lt;Perm.ReadComment &amp;amp; Perm.BanUser&amp;gt;
) {
  // implementation here
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is supposed to be a component that renders a control panel for moderators that have the &lt;code&gt;ReadComment&lt;/code&gt; AND &lt;code&gt;BanUser&lt;/code&gt; permissions but uhhh… what on earth would be the type of &lt;code&gt;1 &amp;amp; 2&lt;/code&gt;? You can have a number that is either a 0 or a 1… but what is a number that is a 0 AND 1, or 1 AND 2? That just doesn’t make any sense. Actually, there &lt;/p&gt;&lt;div&gt;is&lt;/div&gt; a type for &lt;code&gt;0 &amp;amp; 2&lt;/code&gt; and it’s called &lt;code&gt;never&lt;/code&gt;, not very useful because it just doesn’t exist. You can’t have one number be two different numbers at the same time.&lt;p&gt;&lt;/p&gt;&lt;p&gt;For us to be able to implement permissions, the permissions need to be represented by a type that can be both unioned &lt;/p&gt;&lt;div&gt;AND&lt;/div&gt; intersected by each other. Sadly that rules out all primitive types including enums if we’re interested in representing more complex permission restrictions. The good news is objects fit this criteria, even if they do feel a little bit more jank than the alternatives.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Now we need a function that allows us to create a new user type and assign it to a new variable to use as an authorized user.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;type AuthorizeResult&amp;lt;T extends Permissions&amp;gt; =
  | { type: &quot;ok&quot;; user: AuthorizedUser&amp;lt;T&amp;gt; }
  | { type: &quot;fail&quot;; reason: string }

function authorize&amp;lt;T extends Permissions&amp;gt;(
  user: User,
  permission: T
): AuthorizeResult&amp;lt;T&amp;gt; {
  // imagine an actual function implementation here
  if (someCondition) {
    return { type: &quot;ok&quot;, user: user as AuthorizedUser&amp;lt;T&amp;gt; }
  } else {
    return { type: &quot;fail&quot;, reason: &quot;User does not stan loona&quot; }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There’s a lot going on here, so let’s dissect it piece by piece. We’re defining an &lt;code&gt;authorize&lt;/code&gt; function that takes in a regular User and permissions we want to check for, but it’s not returning an &lt;code&gt;AuthorizedUser&lt;/code&gt;. The user might not have the correct authorization level, so we’re telling the compiler that the result might either be a successfully authorized user, or a failure with a reason explaining why. The typechecker &lt;/p&gt;&lt;div&gt;WILL NOT&lt;/div&gt; allow us to access the result of this function without explicitly checking to make sure we successfully got an authorized user out of this.&lt;p&gt;&lt;/p&gt;&lt;p&gt;So the bug we had earlier turns into this with our new system.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;function onSubmit() {
  const result = authorize(user, writeComment)
  if (result.type === &quot;fail&quot;) {
    sendMessage({
      message: &quot;Sorry you can&apos;t write comments!&quot;,
    })
    // agh! we forgot to return again
  }
  submitComment(result.user, form.comment)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But instead of crashing in runtime, this time we get a compile-time error as soon as we make the mistake.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Property &apos;user&apos; does not exist on type &apos;PermissionResult&amp;lt;WRITE_COMMENT&amp;gt;&apos;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We didn’t return from the if statement and the TypeScript compiler couldn’t narrow the type down to an &lt;code&gt;AuthorizedUser&amp;lt;WRITE_COMMENT&amp;gt;&lt;/code&gt;, as soon as we add the missing &lt;code&gt;return&lt;/code&gt; it works again. 🎉 We did it!&lt;/p&gt;&lt;p&gt;This still feels a little bit weird, though. Assigning a new user variable feels unnatural, and this doesn’t look like our original check either. That’s ok, TypeScript gives us a way to narrow the types of variables conditionally using something called &lt;/p&gt;&lt;div href=&quot;https://basarat.gitbook.io/typescript/type-system/typeguard&quot; target=&quot;_blank&quot;&gt;Type Guards&lt;/div&gt;.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Let’s create a type guard for checking permissions.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;function hasPermission&amp;lt;T extends SomePermissions&amp;gt;(
  user: User,
  permission: T
): user is AuthorizedUser&amp;lt;T&amp;gt; {
  return Permission.authorize(user, permission).type === &quot;ok&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;How does the bug look now with the type guard?&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;function onSubmit() {
  // user has type User here
  if (!hasPermission(user, writeComment)) {
    // user has type User here
    sendMessage({
      message: &quot;Sorry you can&apos;t write comments!&quot;,
    })
  }
  // user has type User here
  submitComment(user, form.comment)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we still get an error, nice!&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Type &apos;User&apos; is not assignable to type &apos;AuthorizedUser&amp;lt;WRITE_COMMENT&amp;gt;&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When we return from the if statement properly, we get the same sweet TS typechecker magic.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{h:&amp;quot;8,10&amp;quot;, lines: true}&quot;&gt;function onSubmit() {
  // user has type User here
  if (!hasPermission(user, writeComment)) {
    // user has type User here
    sendMessage({
      message: &quot;Sorry you can&apos;t write comments!&quot;,
    })
    return
  }
  // user has type AuthorizedUser&amp;lt;WRITE_COMMENT&amp;gt; here
  submitComment(result.user, form.comment)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It can infer that we’ve narrowed the type of &lt;code&gt;User&lt;/code&gt; to the correct &lt;code&gt;AuthorizedUser&amp;lt;T&amp;gt;&lt;/code&gt; by performing the check. 👏&lt;/p&gt;&lt;p&gt;This system we set up can work for more complex situations and is capable of dealing with just about any kind of authorization-check-related bug, not just an early return.&lt;/p&gt;&lt;p&gt;Here’s a playground link of a complete implementation if you want to try this out with an editor that displays the correct compiler errors &lt;a href=&quot;https://tsplay.dev/WK8Zzw&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;https://tsplay.dev/WK8Zzw&lt;/a&gt;.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;What we just did here was using a side of static typing that most people don’t even know exists. Yes, static typing can be used to distinguish data apart from each other, but it can also be used to separate &lt;/p&gt;&lt;div&gt;incompatible ideas&lt;/div&gt; with the same underlying data into different types.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Your job as a programmer should not be to check types in code review. You suck at it; that’s the typechecker’s job. Make it do as much of the work for you as possible because it never makes mistakes. Communicating with your compiler is almost as important as communicating with the people you write the code with.&lt;/p&gt;&lt;h2 id=&quot;gotchas&quot;&gt;&lt;a href=&quot;https://xetera.dev/#gotchas&quot;&gt;Gotchas&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;There are a few caveats to this system, of course. Anyone can cast a &lt;code&gt;User&lt;/code&gt; into an &lt;code&gt;AuthorizedUser&lt;/code&gt; to circumvent compiler checks. But checking for the presence of unsafe casts and functions with the wrong permission requirements is a much simpler mental task to do in a code review than having to remember to check every permission-related bug every time permissions are involved.&lt;/p&gt;&lt;p&gt;The goal of this is to be able to constrain the slightly unsafe code to just a few functions that are extensively tested, vs being scattered everywhere around a codebase that gets updated with every new commit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[😠 Misleading educational videos]]></title><link>https://xetera.dev/misleading-educational-videos/</link><guid isPermaLink="false">https://xetera.dev/misleading-educational-videos/</guid><pubDate>Sat, 28 Aug 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/misleading-educational-videos/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;I love the internet as a resource for learning new things. I love YouTube as an easily accessible, exciting source of information for beginners. I have a long article describing &lt;a href=&quot;https://xetera.dev/why-does-school-suck-so-much&quot;&gt;just how much of a fan I am of online learning&lt;/a&gt;, but it comes with its own set of problems.&lt;/p&gt;&lt;p&gt;Teaching is not simple; communicating ideas takes a lot of very intentional effort to pull off successfully. It’s easy for people who don’t have a full grasp of a topic or find it difficult to convey what they do know well to unintentionally spread misleading —or sometimes straight-up incorrect— information. In my experience, most channels that spend time creating online content do their due diligence and make sure what they’re putting out is high quality and correct, but this is not always the case.&lt;/p&gt;&lt;p&gt;I want to specifically talk about one video today, which I think is a pretty egregious example of what I mean.&lt;/p&gt;&lt;div&gt;&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom:56.25%;position:relative;height:0;overflow:hidden;margin-bottom:1.0725rem&quot;&gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/MEyyegfvhwM&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt; &lt;/div&gt;&lt;/div&gt;&lt;h2 id=&quot;whats-wrong-with-this-video&quot;&gt;&lt;a href=&quot;https://xetera.dev/#whats-wrong-with-this-video&quot;&gt;What’s wrong with this video&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Now, right off the bat, the title… I don’t know. It’s a bit weird, but I guess you gotta hustle and get views, right? I don’t like it, but it doesn’t change the content; it’s just a red flag that makes this video stand out to me as potentially low quality. It’s just ever so slightly sus. &lt;/p&gt;&lt;div display=&quot;inline&quot; h=&quot;10,,10&quot;&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;As a quick summary, the person in the video is going through an &lt;a href=&quot;https://github.com/bkimminich/juice-shop&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;OWASP Juice Shop&lt;/a&gt;
setup and demonstrating an injection vulnerability with user creation. It allows him to modify the payload in the user create endpoint to include properties that get sent directly to the database without any validation. This kind of thing can happen on a backend that looks something like this.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;app.post(&quot;/user&quot;, async (req, res) =&amp;gt; {
  // no checks, send everything straight into the database baby
  const result = await db.createUser(req.body)
  res.json(result)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, this is a pretty serious vulnerability, but it’s not realistic for big websites. It can happen with an inexperienced developer using a cringe backend like Express.js where there’s no validation built into the webserver and zero type-safety, but it’s not something you’re going to be running into in the wild very often. Injection is literally #1 in &lt;a href=&quot;https://owasp.org/www-project-top-ten/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;the OWASP list of top 10 web vulnerabilities&lt;/a&gt;, so it’s clearly a big problem. However, simple injection exploits like these are not going to be found in the first place you’d be looking for them, like a sign-up form. You probably don’t make mistakes calculating something like 20 + 10 if you’re double-checking and have people going over your work as well.&lt;/p&gt;&lt;p&gt;The way Loi finds out this vulnerability (I hope that’s his name, I haven’t watched this YouTube channel before) isn’t really discussed, and he tries to sell the process he’s going through as something that works for any website; which is obviously not true, but we can suspend our disbelief in the name of clickbait magic for now. In the video, he points out that the backend is storing sensitive information in the JSON Web Token (JWT) issued to the user and goes through it to find potentially juicy information.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:693px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/7346a7de393ded348ec2c8909e31303d/61c63/jwt_dump.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:65.2%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABqUlEQVQoz52Sa2/aMBiF/f9/y9p9GdIo0i4lCdoYubTAmsQOogRiCoHEKY3vqUwKqrpuH/bqkXV0dM5rWTIIh3GCkhmaTSfT4Y+f0/EExejfwBghmCQoAbps/nsAXXMttRJKCSUeJdtxWSteCFkrLfRbpD6HtdSAYt7oxrhKK6bphvNCNvK9i3TTKEO7olENoFi8lI/US0Y3gu0ExZyuOF1znkt5UPKgFNVvyyx7VRZNjTnbHpsZP+AnngtJpDoo+ahU/UeZbJmUSnJpYPJpzQ7zmm4ZrwTdMFZwxZVu5/TaNqyEAvBhX5UVKUjLNtnns/1uVRQPJdlXJCckJ2VOyi0he1KV1TlclRWYpxle4WyZtdyP0/lNmsLl/HaxuEvvJ+nid2rE7WKZLHGGz2G8wsAah0mMYAQNIQzdKPSiaBpH4xiGEN4hcxoBUXT6JMcwihEYjvzAC3zX9z3fHXjuwPv1bTTsjQI3CHzDzYnAe8F3/VaAgeU4lmP3bcN327l2rK+29cVy+sZ/F7tvtwJcda/a6XzqfLy8vPhw0el0er2e8f9C93O3bT0D0ou+t8tBql0AAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/7346a7de393ded348ec2c8909e31303d/490da/jwt_dump.webp 250w,/static/7346a7de393ded348ec2c8909e31303d/e333e/jwt_dump.webp 500w,/static/7346a7de393ded348ec2c8909e31303d/65152/jwt_dump.webp 693w&quot; sizes=&quot;(max-width: 693px) 100vw, 693px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/7346a7de393ded348ec2c8909e31303d/63868/jwt_dump.png 250w,/static/7346a7de393ded348ec2c8909e31303d/0b533/jwt_dump.png 500w,/static/7346a7de393ded348ec2c8909e31303d/61c63/jwt_dump.png 693w&quot; sizes=&quot;(max-width: 693px) 100vw, 693px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/7346a7de393ded348ec2c8909e31303d/61c63/jwt_dump.png&quot; alt=&quot;a screenshot of JWT claims showing multiple fields that could be considered sensitive&quot; title=&quot;a screenshot of JWT claims showing multiple fields that could be considered sensitive&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;This isn’t an incorrect observation since there’s a &lt;code&gt;password&lt;/code&gt; and &lt;code&gt;totpSecret&lt;/code&gt; field in there, which are definitely scary-sounding fields I don’t want to see in my client. But the critical thing to note here is that this layout of the JWT with all the unexpected “sensitive” content lets an attacker infer that there might be a missing sanitization step between fetching user data and creating a JWT. The JWT claims might represent the exact structure of what a user row in the database might look like since a carefully crafted token would probably not contain these fields. The data stored in the JWT is &lt;/p&gt;&lt;div&gt;NOT&lt;/div&gt; a vulnerability or a security problem by itself, as these fields should only be accessible by the user the token is being issued to. It’s just a strong clue for an attacker that gives insight into what the backend might be doing wrong.&lt;p&gt;&lt;/p&gt;&lt;p&gt;The step of inspecting the JWT gave Loi an idea of what the database schema of the site looks like, and it let him make a good guess for how he could change a payload that might be lacking validation from its inputs; the same way it lacked validation for its outputs. It’s not actually a part of the vulnerability he ends up exploiting, and yet, he keeps going on about storing sensitive information in a JWT the entire time and never once mentions injection, which is the real culprit here. &lt;/p&gt;&lt;div&gt;Why?&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;He later goes to the user registration page, pulls up burp suite, and talks about how the JWT thing is making it possible for him to create a new user with premium, which makes no sense. The roles in the JWT are not insecure or sensitive. It’s not uncommon to store user roles in a JWT as it’s signed, and a user can’t change it. If there was proper validation being done, the JWT would’ve made zero difference, and the exploit wouldn’t be possible. These two things are not in the least bit related to each other. This exploit is still possible with or without a JWT storing information that is not even sensitive to begin with.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div color=&quot;text.400&quot; font-size=&quot;md&quot;&gt;The only problems that arise from storing user roles in tokens are logistical, and not security-related. For example, if you store roles in a token, you have to reissue the user a new token when you want to change their roles which can be kind of a pain to deal with if you don&apos;t have a flexible setup for that sort of thing.&lt;/div&gt;&lt;/div&gt;&lt;p&gt;It’s also possible to set claims on a token without straight-up dumping an entire DB row into it and giving attackers insight into your DB schema and your app’s security flaws.&lt;/p&gt;&lt;p&gt;This was clearly something that confused viewers, seen by comments like these from people who convinced themselves that they just became experts on stateless authentication after watching a video of an exploit that had nothing to do with JWTs.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:443px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/f421ffd84dfdb5b63468b1bef570e5e7/a120c/jwt_comment.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:31.2%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA2ElEQVQY032OTU7FMAyEewYgqR0ncSo1Jajpb9r07dodiFtw/0ug9iFY8T6NLHuk0bgAACGkkCWRds4xM1urNaFCIlJKlRcA57h0P08KRHxfxljZ2PX7sW/b7Tj2cRxDCDG2bdtaa4k0XShSxhhm/gkLWX59fhxjtFWVUuq6Iecc+z6vedu2Ja95XZYlpzRP85ymaV3z0Pf38gIAnoV8ehG+rhtfO6ND4w3h2EVmK6V89DYAKESA0nDFYbBvyfho2uzCgKf/iOJvRULnyUfkWr8mdM1vw3/hb9KYLS3fTRzIAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/f421ffd84dfdb5b63468b1bef570e5e7/490da/jwt_comment.webp 250w,/static/f421ffd84dfdb5b63468b1bef570e5e7/1d27c/jwt_comment.webp 443w&quot; sizes=&quot;(max-width: 443px) 100vw, 443px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/f421ffd84dfdb5b63468b1bef570e5e7/63868/jwt_comment.png 250w,/static/f421ffd84dfdb5b63468b1bef570e5e7/a120c/jwt_comment.png 443w&quot; sizes=&quot;(max-width: 443px) 100vw, 443px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/f421ffd84dfdb5b63468b1bef570e5e7/a120c/jwt_comment.png&quot; alt=&quot;Youtube comment: &amp;quot;This is more of [a] tutorial about how to not use JWT&amp;quot;&quot; title=&quot;Youtube comment: &amp;quot;This is more of [a] tutorial about how to not use JWT&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:881px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/6587a76e2794f655e0ab61e02fe24e64/96658/jwt_comment_2.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:11.6%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAAsTAAALEwEAmpwYAAAATklEQVQI102L0QqAIBRD/Qt70Np2s7iJ0P9/XaQJ7WGMw1m43L3duzcedaWZqBn2SPYnps/IOYUlxk0FxXlWWAG28RoqAPId6o3JSaWUH+RzD+um63GYAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/6587a76e2794f655e0ab61e02fe24e64/490da/jwt_comment_2.webp 250w,/static/6587a76e2794f655e0ab61e02fe24e64/e333e/jwt_comment_2.webp 500w,/static/6587a76e2794f655e0ab61e02fe24e64/e7425/jwt_comment_2.webp 881w&quot; sizes=&quot;(max-width: 881px) 100vw, 881px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/6587a76e2794f655e0ab61e02fe24e64/63868/jwt_comment_2.png 250w,/static/6587a76e2794f655e0ab61e02fe24e64/0b533/jwt_comment_2.png 500w,/static/6587a76e2794f655e0ab61e02fe24e64/96658/jwt_comment_2.png 881w&quot; sizes=&quot;(max-width: 881px) 100vw, 881px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/6587a76e2794f655e0ab61e02fe24e64/96658/jwt_comment_2.png&quot; alt=&quot;Youtube comment: &amp;quot;JWT tokens should be used by the user, it&apos;s just that the tokens should never include data that is private&amp;quot;&quot; title=&quot;Youtube comment: &amp;quot;JWT tokens should be used by the user, it&apos;s just that the tokens should never include data that is private&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;I understand that these types of videos are meant to wow beginners and maybe get them excited about security, which is awesome! But the way this video is presented seems like it’s meant more for experienced devs, with the way it’s filled with a lot of technical jargon that would not be very useful for a beginner. It almost feels like it’s an attempt to impress inexperienced people with a bunch of complicated technical stuff by someone who forgot that there are people who understand what he’s talking about watching the video. I don’t like this at all. This person is clearly experienced in this field and is someone that plenty of people look up to as an expert, yet he’s not doing a good job communicating his knowledge clearly.&lt;/p&gt;&lt;p&gt;I’m all for showing cool stuff to people to get them interested in a field. But there are plenty of beginners who are still learning about these concepts who consume the content people like this guy create as a foundation for their knowledge, and that has some serious implications in situations like these. There’s a way to combine being engaging and being correct, but it’s not always easy. If you’re willing to compromise this much on the latter part, I don’t think you should be creating educational content, or at the very least, content that leads viewers to believe they just learned something new from an expert.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;Btw, huge shoutout to the one person in the comments who actually understood what was going on lmao.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:678px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/4c9de6ce57cf2010f03bde99e90fe3f4/38cea/jwt_comment_good.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:36%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAAsTAAALEwEAmpwYAAABFklEQVQY03XPwXKDIBQFUL/BCJi0EEANJGA7okDsJIYYNfn/L+po2k42PYs7b3Hv4kVFTotdobUmhHDGN+s1AABAuMScrxBC6YsoY1ipg/fHqjLWWu99Y23TNHXd1KZ2zjlrj9637dfHxyfG+HUfxfHqoPQ43S/hcr9PfX/r+/56vY7jeLv1bdvupdzPDkopxliapuvFPIYQCiHtj8aYuqqMMcY5p5TijK1+xXGcJAlcPF+IAEi0LkMIlxCGYXg8HtM0hRDGYTydzt4fz7Ou6zqtdVEUu5kQQmwJiRBClNKyLKUUGOPtllJKCSHLwTjPOGd5nnPOsizjnP8lxu8RBEBKKYWgjGUZf9tsIIQIIYgQ/Bd4dr4BIro9uBG6A/wAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/4c9de6ce57cf2010f03bde99e90fe3f4/490da/jwt_comment_good.webp 250w,/static/4c9de6ce57cf2010f03bde99e90fe3f4/e333e/jwt_comment_good.webp 500w,/static/4c9de6ce57cf2010f03bde99e90fe3f4/2c401/jwt_comment_good.webp 678w&quot; sizes=&quot;(max-width: 678px) 100vw, 678px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/4c9de6ce57cf2010f03bde99e90fe3f4/63868/jwt_comment_good.png 250w,/static/4c9de6ce57cf2010f03bde99e90fe3f4/0b533/jwt_comment_good.png 500w,/static/4c9de6ce57cf2010f03bde99e90fe3f4/38cea/jwt_comment_good.png 678w&quot; sizes=&quot;(max-width: 678px) 100vw, 678px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/4c9de6ce57cf2010f03bde99e90fe3f4/38cea/jwt_comment_good.png&quot; alt=&quot;Experienced security person ripping into the flaws of the video&quot; title=&quot;Experienced security person ripping into the flaws of the video&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🏫 Why does school suck so much?]]></title><link>https://xetera.dev/why-does-school-suck-so-much/</link><guid isPermaLink="false">https://xetera.dev/why-does-school-suck-so-much/</guid><pubDate>Sat, 21 Aug 2021 10:07:10 GMT</pubDate><enclosure url="https://xetera.dev/why-does-school-suck-so-much/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;There’s a quote that every breathing human ever has either heard of before or recited for themselves that goes:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;And I agree with the premise, but I think this is a pretty outdated saying and I’d like to propose a third alternative that is inspired by the words of the famous philosopher Ron Swanson.&lt;/p&gt;&lt;div mb=&quot;8&quot;&gt;&lt;div borderradius=&quot;md&quot; as=&quot;video&quot; width=&quot;100%&quot; src=&quot;https://media.vlipsy.com/vlips/GqLsYMoQ/480p.mp4&quot; playsinline=&quot;&quot; controls=&quot;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Don’t teach a man to fish. He’s a grown man; he can learn to fish on his own. Instead, show him why he might be interested in it over something else. Show him why you’re passionate about fishing. Take him out for a boat ride, and get him excited about how good it feels when you catch something after patiently waiting for hours. Describe to him the details of fishing that make it feel so rewarding to sit with a pole in your hand for a whole day. But &lt;/p&gt;&lt;div&gt;please&lt;/div&gt;, for the love of God, don’t teach him how to fish. He doesn’t need you for that.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Admittedly, this version doesn’t quite roll off the tongue, so I’m probably not going to be remembered for it when I die, but I think it touches on an important idea that I want to discuss.&lt;/p&gt;&lt;h2 id=&quot;why-we-teach&quot;&gt;&lt;a href=&quot;https://xetera.dev/#why-we-teach&quot;&gt;Why we teach&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;For a very long time, most of teaching was something we had to do out of necessity. If you wanted to survive, you had to learn how to hunt, how to avoid predators, how to gather supplies for your tribe; someone was equally as obligated to teach those things to you. You learned what you had to learn, so you could do what you need to do. Sure, even in the early days, people were concerned with arts and other non-essential skills, but they were not much more than side projects. Something you did when you were free from the work someone or something forced you into doing. If little Ugubwe wanted to eat that night, he had to hunt with the men of the tribe, and then he could learn to paint on the cave walls from the tribe elders later if he wanted to.&lt;/p&gt;&lt;p&gt;As of fairly recently —specifically during the time of the industrial revolution— we learned to channel this idea into institutions capable of growing a large population of little people into skilled factory workers years down the line. This wasn’t so much based on necessity; we realized that like… I don’t know man like this learning thing might be a good idea I don’t know… So we went ahead and set up schools to actually be usable by the general public and came up with the &lt;/p&gt;&lt;div&gt;incredible idea&lt;/div&gt; that being born into a family that has multiple servants should not be a pre-requisite to learning how to read. You still didn’t get to paint on the cave walls on your own terms though. You learned the absolute basics of literacy and whatever skills you needed to become a good, obedient factory worker.&lt;p&gt;&lt;/p&gt;&lt;div caption=&quot;A classroom of girls in the Victorian era wishing they could be doing literally anything else right now.&quot;&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:736px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/83e487d4a7e8374c50578ae6f7d066f4/97cfc/victorian.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:63.2%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/2gAMAwEAAhADEAAAAaorvYQzyf/EABoQAAICAwAAAAAAAAAAAAAAAAECABEDEjH/2gAIAQEAAQUCL7SiDZWK5E5jdyzf/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8BR//EABkQAAMBAQEAAAAAAAAAAAAAAAABIQIRUf/aAAgBAQAGPwLw4istQ95h1s//xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhQTGB/9oACAEBAAE/IWyFzlTQMCXEt+BKQoXGe4bcibYz/9oADAMBAAIAAwAAABDUz//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/EFf/xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQIBAT8QwI//xAAbEAEBAAIDAQAAAAAAAAAAAAABEQAhMUFRkf/aAAgBAQABPxBSDRSqnu8mL7csujFFGqmxOqJkBIX3xqPbU2MXnFsU+Z//2Q==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/83e487d4a7e8374c50578ae6f7d066f4/490da/victorian.webp 250w,/static/83e487d4a7e8374c50578ae6f7d066f4/e333e/victorian.webp 500w,/static/83e487d4a7e8374c50578ae6f7d066f4/a2eb6/victorian.webp 736w&quot; sizes=&quot;(max-width: 736px) 100vw, 736px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/83e487d4a7e8374c50578ae6f7d066f4/0479a/victorian.jpg 250w,/static/83e487d4a7e8374c50578ae6f7d066f4/41099/victorian.jpg 500w,/static/83e487d4a7e8374c50578ae6f7d066f4/97cfc/victorian.jpg 736w&quot; sizes=&quot;(max-width: 736px) 100vw, 736px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/83e487d4a7e8374c50578ae6f7d066f4/97cfc/victorian.jpg&quot; alt=&quot;victorian girls in captivity&quot; title=&quot;victorian girls in captivity&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/div&gt;&lt;p&gt;This way of learning worked well for its intended purpose for many &lt;/p&gt;&lt;div&gt;thousands&lt;/div&gt; of years, but because it was motivated by necessity or covering the absolute basics, you were never asked about what it was that you wanted to learn. You weren’t nudged into discovering a passion for yourself. You were either given a task you had to do for a lifetime or had to find out what that was if you wanted to survive.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Now in &lt;/p&gt;&lt;div as=&quot;time&quot;&gt;2023&lt;/div&gt;, as our global economies are transitioning out of the &lt;div text=&quot;secondary sector&quot; type=&quot;Noun&quot; title=&quot;Secondary Sector&quot; color=&quot;orange.500&quot; whitespace=&quot;nowrap&quot;&gt;In the &lt;div&gt;three-sector model&lt;/div&gt;, the secondary sector refers to an economy that is based around the conversion of raw material to products through factories and processing.&lt;/div&gt; and into the &lt;div text=&quot;tertiary and quaternary sector&quot; type=&quot;Noun&quot; title=&quot;Tertiary Sector&quot; color=&quot;blue.400&quot; whitespace=&quot;nowrap&quot;&gt;In the &lt;div&gt;three-sector model&lt;/div&gt;, the tertiary sector and above refer to an economy that is primarily focused around the sales and marketing of goods produced in the secondary sector, as well as the creation and sharing of information.&lt;/div&gt;, we’re finding that there is objectively a more diverse pool of work to be done compared to what our parents and grandparents had to do. Statistically speaking, if you’re in middle school today, by the time you’re ready to join the workforce, you’re most likely going to be working a job that doesn’t even exist yet. When it comes to career choice, we can now choose from a plethora of options, and we live in an era where all the information we need to learn new things is at our fingertips. Yet, for some reason, the fisherman is &lt;strong&gt;still trying to teach us to fish&lt;/strong&gt; even though we have the option to do anything else.&lt;p&gt;&lt;/p&gt;&lt;h2 id=&quot;what-if-i-dont-want-to-become-a-fisherman&quot;&gt;&lt;a href=&quot;https://xetera.dev/#what-if-i-dont-want-to-become-a-fisherman&quot;&gt;What if I don’t want to become a fisherman?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Remember when you were a kid and you heard &lt;em&gt;that&lt;/em&gt; question? You know the one I’m talking about…&lt;/p&gt;&lt;div textalign=&quot;center&quot; color=&quot;brand.100&quot; mb=&quot;6&quot; font-weight=&quot;black&quot; font-size=&quot;lg,,xl,2xl&quot;&gt;So Jakey, what do you want to be when you grow up?&lt;/div&gt;&lt;p&gt;Every kid’s nightmare. Of the million things you could choose as a profession, chances are you had no idea what you wanted to be when you grew up. What were you even interested in? &lt;/p&gt;&lt;div text=&quot;Video games&quot; color=&quot;purple.400&quot;&gt;I&apos;m assuming that the people who&apos;d be interested in reading my blog were kids when video games were a thing.&lt;/div&gt;? Art? Chatting with your friends about random nonsense on Skype late on a school night until your dad finally walked into your room at 3 AM and confiscated your phone while muttering something under his breath about how irresponsible you are? Were you ever given an opportunity where you could discover new things you liked that fell outside your comfort zone of interests as a kid? Probably not. We have so little time to explore ourselves, the world, and our interests while going through school. Yet, for some reason, we assume that kids will have some idea about what they’re going to be doing for a living after high school or college when we never bother to allow them to discover their passions. This phenomenon did not use to be relevant in the past, but I would like to argue it certainly is now.&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Hope you didn’t forget about your homework of figuring out what you want to do in life. You had 12 years to hand it in!&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;When we were still hunter and gatherers, at least after you learned to hunt, you had all the skills necessary to become a hunter. How does this translate to school now? Do students end up developing an interest in the fields they spend a long time learning? Do all kids want to become English teachers and biologists? Do these courses prepare them for the future where they might have an opportunity to work in a field they actually enjoy? Oh, I’m sorry, were you sleeping in your &lt;/p&gt;&lt;div&gt;investment banking&lt;/div&gt; class? Maybe you should pay more attention in your &lt;div&gt;forensic investigation&lt;/div&gt; class next time because not only do you not have any of the skills necessary to work in these fields; you probably don’t even know what it means to do those things as a career.&lt;p&gt;&lt;/p&gt;&lt;p&gt;The bottom line is that school does &lt;strong&gt;absolutely nothing&lt;/strong&gt; to expose you to different fields you could be interested in exploring. Even though educational institutions are capable of helping you explore various interests with an educator who could help guide you into discovering a passion, that’s rarely ever the case. You will learn the basics of a few subjects some boomers decided you should know many years ago —with a few revisions here and there— and you will be released into the wild with no valuable knowledge to further your career or your desire to learn.&lt;/p&gt;&lt;p&gt;Also, I don’t mean valuable knowledge in the same way an annoying middle-schooler would talk about it in science class going:&lt;/p&gt;&lt;div&gt;&lt;div username=&quot;Class clown&quot; number=&quot;+1 (234) 567-8910&quot; color=&quot;rgb(230, 159, 115)&quot; time=&quot;9:21 AM&quot; messages=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div username=&quot;D student&quot; number=&quot;+123 (456) 689-1011&quot; color=&quot;rgb(120, 159, 115)&quot; time=&quot;9:21 AM&quot; messages=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Detention magnet&quot; number=&quot;+1 (234) 567-1234&quot; color=&quot;blue.400&quot; time=&quot;9:22 AM&quot; messages=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div color=&quot;rgb(120, 159, 115)&quot; time=&quot;9:22 AM&quot; messages=&quot;I hate this job so much.&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;I’m referring to the kind of information &lt;strong&gt;YOU&lt;/strong&gt; consider to be valuable. Whether that’s the knowledge that will help you succeed in life, like writing a good resume, or knowledge you find fun and engaging just for the sake of it. If you want to find something you’re interested in pursuing in the long term and you think school is going to help you with that, I have some bad news for you.&lt;/p&gt;&lt;p&gt;All of this happens because there’s one important thing that’s changed in the last few decades that educational institutions have not managed to keep up with, which is that information is now easily accessible online. The benefits of “giving” someone knowledge aren’t as pronounced when you can simply learn those things yourself with little effort. Combined with the increase of the “surface area” of information you need to know, it’s clear that students need guidance and mentorship to navigate their way to what will work well for them, not knowledge. You can learn things from anywhere; that’s not the issue anymore.&lt;/p&gt;&lt;h2 id=&quot;how-we-enjoy-being-taught&quot;&gt;&lt;a href=&quot;https://xetera.dev/#how-we-enjoy-being-taught&quot;&gt;How we enjoy being taught&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The reason I feel so strongly about this topic is that I know most people —if not all— are interested in learning and are curious by nature. School does a terrible job at bringing out this incredible quality in us, but it’s there. One of the best places to witness this is in the comments section of educational &lt;a href=&quot;https://www.youtube.com/watch?v=OxGsU8oIWjY&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;math and science videos&lt;/a&gt; on YouTube, which many people still label as &lt;/p&gt;&lt;div&gt;procrastination&lt;/div&gt; and &lt;div&gt;not real learning&lt;/div&gt; to this day.&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:462px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/c7529f02edaef0bc3c9123d00a92e1a2/e389b/youtube-comment.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:30%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA20lEQVQY033OMXLDIBCFYZ0hk2GXRbBYsuwIAQEBKlzIVaocKZfPOC7scZGv+2eLfR0gSgABwMzWHuzBKiJFNyAe4BbwlICI3SDpZw5fmj9rve7Xfd+D94tfQvDTNBljrGXDbNgYY5jt3w+rdQ8AXS/xm4dIajydUkprqbWsPoSUcmutlFrWnPOaUo4x1lpbKW3b5vlDCNEB4hvAuxDeL9NxHFgvbtZKRu90398XvnjMRkRClIi9YX3O2m36vBrXbLyQUvhCIsqbe3VPByI+qmGW2qrB0ehQEv7rF3ZULN5m23joAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/c7529f02edaef0bc3c9123d00a92e1a2/490da/youtube-comment.webp 250w,/static/c7529f02edaef0bc3c9123d00a92e1a2/1e782/youtube-comment.webp 462w&quot; sizes=&quot;(max-width: 462px) 100vw, 462px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/c7529f02edaef0bc3c9123d00a92e1a2/63868/youtube-comment.png 250w,/static/c7529f02edaef0bc3c9123d00a92e1a2/e389b/youtube-comment.png 462w&quot; sizes=&quot;(max-width: 462px) 100vw, 462px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/c7529f02edaef0bc3c9123d00a92e1a2/e389b/youtube-comment.png&quot; alt=&quot;Youtube comment that reads &amp;quot;I can&apos;t believe I&apos;m watching this video for entertainment&amp;quot;&quot; title=&quot;Youtube comment that reads &amp;quot;I can&apos;t believe I&apos;m watching this video for entertainment&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;You can see the amazement in people as they realize that learning is an incredible feeling and that &lt;strong&gt;school doesn’t have to be synonymous with education&lt;/strong&gt;. Unfortunately, that is the way most of us feel, as we get put through this system starting as early as age 5, and it leads to a painful internal conflict for kids who realize the current education system isn’t their cup of tea and they don’t perform well in school because of it. They often think that they are just too dumb to understand concepts like math and science and arrive at the inevitable conclusion that they don’t like &lt;/p&gt;&lt;div&gt;learning&lt;/div&gt;.&lt;p&gt;&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div username=&quot;Tzuyu&quot; rolecolor=&quot;green.500&quot; date=&quot;2:25 PM&quot; avatar=&quot;[object Object]&quot; messages=&quot;DUDE,[object Object],[object Object],Man if Ms. Connell taught us math like this I would&apos;ve had a degree in math already&quot; reactions=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Xetera&quot; rolecolor=&quot;purple.500&quot; date=&quot;2:25 PM&quot; messages=&quot;But you don&apos;t even have a highschool diploma yet&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Tzuyu&quot; rolecolor=&quot;green.500&quot; date=&quot;2:25 PM&quot; avatar=&quot;[object Object]&quot; messages=&quot;Shut up,watch the video,[object Object],[object Object]&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Obviously this isn’t specific to YouTube, but there’s clearly something about this style of learning and exposure of new concepts that touches people’s hearts to the point where those who don’t see themselves as an average school fan find themselves to be an average YouTube enjoyer. So what is it about this medium that feels so different from school? Let’s look at that question by exploring the differences between what it means to be educator in the school system vs online media.&lt;/p&gt;&lt;h3 id=&quot;educational-differences&quot;&gt;&lt;a href=&quot;https://xetera.dev/#educational-differences&quot;&gt;Educational Differences&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;YouTube forces content creators to compete for your attention at any given moment. If the video you’re looking at is not enticing enough, chances are you’re just going to click on the next recommended video. Content creators win customers over by getting them to subscribe, but they still need to work hard to make sure that the videos that they’re putting out continue to be engaging for their audience. As a viewer, you have the opportunity to explore a tremendous amount of alternative content with little work on your end. You can also choose not to watch YouTube anymore, at which point the content creator still loses a customer. There’s no single point where a creator gets to relax and stop caring about how engaging their audience thinks their work is because the customer lifecycle can break at any moment.&lt;/p&gt;&lt;p&gt;Teaching online is also difficult work, and naturally, the people who choose to go through with it are those who have a special knack for teaching and content creation. I can only think of a single one of my college professors who could even imagine of doing what they do at school on the internet where you have to actually be good at explaining ideas to see any amount of success.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div font-size=&quot;md&quot; color=&quot;text.300&quot;&gt;Shoutout to my man Henry Carnie, one of the only college professors I had who was actually good at what he does and got me interested in History.&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Things go a little differently for formal education.&lt;/p&gt;&lt;p&gt;First, society expects you to attend school. &lt;/p&gt;&lt;div&gt;Don’t believe me?&lt;/div&gt; What’s the kind of reaction do you think you get after you tell a family member that you don’t want to go to university?&lt;p&gt;&lt;/p&gt;&lt;div&gt;&lt;div number=&quot;+1 (234) 567-8910&quot; time=&quot;10:21 PM&quot; messages=&quot;Hey auntie, I decided to drop out of school, it just wasn&apos;t for me.&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Sophie&quot; number=&quot;+い (四八八) 九二三一五&quot; color=&quot;rgb(230, 159, 115)&quot; time=&quot;10:22 PM&quot; messages=&quot;WHAT? Why?,Have you told your mom yet?,What are you gonna do now?,Did we pay for your highschool just so you can drop out of college?,I can&apos;t believe you&apos;d be so irresponsible&quot;&gt;&lt;/div&gt;&lt;div time=&quot;10:24 PM&quot; messages=&quot;Ok good talk,bye&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;You need a reason to choose not to go to school, and a good one at that too. That’s an &lt;/p&gt;&lt;div&gt;incredible&lt;/div&gt; leverage for educational institutions. For that reason, schools have to do relatively little to ensure that new students keep coming in year after year in terms of enticing students other than existing in a convenient physical location and not having a bad reputation.&lt;p&gt;&lt;/p&gt;&lt;p&gt;They also win over customers when students enroll, and that’s generally where the effort they have to put in ends. Schools don’t have to care about how engaging you feel the education is because they have no reason to. An enrolled student will continue attending unless the school does something catastrophic, and when that does happen, it’s usually not an education-related issue either.&lt;/p&gt;&lt;p&gt;Wait, what’s that? You’re saying that you always have the power to choose to attend a better school as a customer/student? &lt;/p&gt;&lt;div&gt;Uhuh&lt;/div&gt;, which school are you going to move to, the one that’s the &lt;strong&gt;second&lt;/strong&gt; closest to your house? Gosh, I hope the education style there is better than the previous, even though that school has no reason to care either. Fine, you could choose to attend an online school, so you’re not restricted by the physical location, but how are you supposed to tell apart an online school with a teaching style that resonates with you? There’s no metric for this kind of thing. Schools get classified by prestige and cost, and we all know prestige is not an indicator of whether or not a school sucks to attend by any means.&lt;p&gt;&lt;/p&gt;&lt;p&gt;There’s an industry standard set by traditional schools where, as a student of the school you attend, your opinions and satisfaction of these institutions are nowhere to be found in the list of things that influence their decision making. The schools make themselves look good doing the exact same thing they’ve done for the past 200 years, just with different curriculums. Your aunts and uncles, along with the rest of society, continue to pressure you to attend them year after year.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Your mom also went to UCI sweetie; you should apply there too.&lt;/p&gt;&lt;/blockquote&gt;&lt;div mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;This stark contrast between the two types of education goes a long way to explain why students have been desperate for an alternative but haven’t been able to push for any meaningful change to get what &lt;/p&gt;&lt;div&gt;they&lt;/div&gt; want to be prioritized. I believe that as remote learning starts to become more common and the importance of having a degree begins to decrease, there’s going to be a major shift in how we do education at the undergraduate level and below. Students, for the first time in a long while, are going to start looking for an alternative way of learning that satisfies their own needs instead of someone else’s.&lt;p&gt;&lt;/p&gt;&lt;p&gt;I can assure you that schools have done less to drive interest in civil engineering on a per-capita basis than this YouTube channel has. These viewers and educators are the ones who will be leading the slow transformation of the education standards around the world in the next 50 years.&lt;/p&gt;&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom:56.25%;position:relative;height:0;overflow:hidden;margin-bottom:1.0725rem&quot;&gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/yZwfcMSDBHs&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt; &lt;/div&gt;&lt;p&gt;As some final thoughts, if you’re still in school, I highly encourage you to do your best to explore different fields you might be interested in by yourself instead of waiting for school to do it for you. One of the most liberating feelings in the world is knowing that you can learn anything you need without being dependent on someone teaching you the curriculum. When you have the freedom to explore the things &lt;/p&gt;&lt;div&gt;you&lt;/div&gt; like, learning no longer becomes a chore.&lt;p&gt;&lt;/p&gt;&lt;p&gt;If you know you like eating fish, don’t wait for someone to give you a fish or teach you fishing. Just Google it and learn it by yourself.&lt;/p&gt;&lt;div icon=&quot;[object Object]&quot; title=&quot;Footnote&quot;&gt;&lt;div color=&quot;text.300&quot; font-size=&quot;md&quot;&gt;Try to take what I&apos;ve written here with a grain of salt. I never finished my degree and I&apos;m obviously projecting my own experiences in the education system. I&apos;m also heavily biased towards a way of learning that works for me and isn&apos;t compatible with the traditional school education system.&lt;/div&gt;&lt;div color=&quot;text.300&quot; font-size=&quot;md&quot;&gt;I recognize that this isn&apos;t the case for everyone out there and that everyone has their way of learning that works with or without a formal education system. I&apos;m only interested in helping people find out what that style is for themselves and not necessarily pushing my preferred method onto anyone else.&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🤖 Bot Taxonomy]]></title><link>https://xetera.dev/bot-taxonomy/</link><guid isPermaLink="false">https://xetera.dev/bot-taxonomy/</guid><pubDate>Sat, 21 Aug 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/bot-taxonomy/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Bots and automation have been something I’ve been fascinated with ever since I started programming. I got into it by looking into Discord bots and quickly learned about things like scraping and other kinds of automation to add new functionality to different tools I was working on at the time. I eventually ended up getting into building scalpers to pay for my college tuition, which was an interesting experience but not something I enjoyed doing (like college itself). Today, I still work in a field that involves botting, just on the other side of the table.&lt;/p&gt;&lt;p&gt;There are many different kinds of bots whose tasks range from crawling the internet to make websites accessible for everyone to making businesses lose &lt;/p&gt;&lt;div&gt;as much money as possible&lt;/div&gt;. The story of bots on the internet is one made up of protagonists, antagonists, and countless supporting characters; villains who try to pillage metaphorical cities for gold and wreckless heroes who put everyone else at risk in order to save the day.&lt;p&gt;&lt;/p&gt;&lt;p&gt;So, how common are bots on the internet? Well, it’s hard to tell, but it seems that:&lt;/p&gt;&lt;div href=&quot;https://theweek.com/articles/454320/62-percent-all-web-traffic-comes-from-bots&quot; rel=&quot;noopener nofollower&quot; target=&quot;_blank&quot; color=&quot;text.100&quot;&gt;&lt;style data-emotion=&quot;css mz9k7c&quot;&gt;.css-mz9k7c{font-family:var(--chakra-fonts-heading);font-weight:var(--chakra-fontWeights-bold);line-height:1.33;margin-bottom:var(--chakra-space-6);font-size:var(--chakra-fontSizes-xl);}@media screen and (min-width: 30em){.css-mz9k7c{font-size:var(--chakra-fontSizes-2xl);}}@media screen and (min-width: 48em){.css-mz9k7c{line-height:1.2;}}@media screen and (min-width: 62em){.css-mz9k7c{font-size:var(--chakra-fontSizes-3xl);}}&lt;/style&gt;&lt;h2 class=&quot;chakra-heading css-mz9k7c&quot;&gt;62% of all web traffic comes from bots&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; style=&quot;margin-left:5px;display:inline;vertical-align:top&quot; height=&quot;28&quot; width=&quot;28&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h6zm11-3v8h-2V6.413l-7.793 7.794-1.414-1.414L17.585 5H13V3h8z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/h2&gt;&lt;/div&gt;&lt;p&gt;I’ll admit, that’s a slightly dubious number. There are other figures from different journals that are way off from this one but seeing as there are so many bots out there, I figured I’d like to categorize them and the rich ecosystem they exist in to see what they’re all about.&lt;/p&gt;&lt;p&gt;I will be using an extremely scientifically rigorous model created by the brightest philosophers and &lt;/p&gt;&lt;div text=&quot;botanists&quot; color=&quot;green.300&quot;&gt;&lt;style data-emotion=&quot;css j7qwjs&quot;&gt;.css-j7qwjs{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}&lt;/style&gt;&lt;div class=&quot;css-j7qwjs&quot;&gt;&lt;style data-emotion=&quot;css x1sij0&quot;&gt;.css-x1sij0{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;}&lt;/style&gt;&lt;div class=&quot;css-x1sij0&quot;&gt;&lt;style data-emotion=&quot;css cniq7b&quot;&gt;.css-cniq7b{font-family:var(--chakra-fonts-heading);font-weight:var(--chakra-fontWeights-bold);line-height:1.33;margin-right:var(--chakra-space-2);font-size:var(--chakra-fontSizes-md);}@media screen and (min-width: 48em){.css-cniq7b{line-height:1.2;}}&lt;/style&gt;&lt;h2 class=&quot;chakra-heading css-cniq7b&quot;&gt;Botany&lt;/h2&gt;&lt;style data-emotion=&quot;css 63k2u9&quot;&gt;.css-63k2u9{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;border-color:var(--chakra-colors-borderSubtlePrimary);border-width:1px;border-radius:var(--chakra-radii-md);-webkit-padding-start:var(--chakra-space-2);padding-inline-start:var(--chakra-space-2);-webkit-padding-end:var(--chakra-space-2);padding-inline-end:var(--chakra-space-2);}&lt;/style&gt;&lt;div class=&quot;css-63k2u9&quot;&gt;&lt;style data-emotion=&quot;css 1y8fdaw&quot;&gt;.css-1y8fdaw{font-size:var(--chakra-fontSizes-xs);color:var(--chakra-colors-text-400);}&lt;/style&gt;&lt;p class=&quot;chakra-text css-1y8fdaw&quot;&gt;Noun&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;p class=&quot;chakra-text css-0&quot;&gt;The scientific study of bots.&lt;/p&gt;&lt;style data-emotion=&quot;css uhamma&quot;&gt;.css-uhamma{color:var(--chakra-colors-gray-500);font-size:11px;}&lt;/style&gt;&lt;p class=&quot;chakra-text css-uhamma&quot;&gt;This is real btw don&apos;t look this one up.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt; of our generation to explain where I place different aspects of the automation ecosystem in (my) moral system.&lt;p&gt;&lt;/p&gt;&lt;div&gt;&lt;div title=&quot;😇 Lawful Good&quot; options=&quot;Googlebot,DDG Crawler,Bingbot&quot; subtitle=&quot;Google &amp;amp; other search engines pretending to be relevant&quot;&gt;&lt;/div&gt;&lt;div title=&quot;😇 Neutral Good&quot; subtitle=&quot;Bot protection as a service&quot; options=&quot;Cloudflare,Datadome,Imperva,Akamai&quot;&gt;&lt;/div&gt;&lt;div title=&quot;😇 Chaotic Good&quot; subtitle=&quot;Port scanning as a service&quot; options=&quot;[object Object],[object Object]&quot;&gt;&lt;/div&gt;&lt;div title=&quot;🙄 Lawful Neutral&quot; subtitle=&quot;Home automation&quot; options=&quot;IoT (Internet of Things),Home assistant&quot;&gt;&lt;/div&gt;&lt;div title=&quot;🙄 True Neutral&quot; subtitle=&quot;Independently run bots for small-scale automation&quot; options=&quot;The 50 line python code your friend wrote to make an anime command for his Discord bot&quot;&gt;&lt;/div&gt;&lt;div title=&quot;🙄 Chaotic Neutral&quot; subtitle=&quot;Proxy and abuse tooling vendors&quot; options=&quot;Oxylabs,Luminati,2Captcha&quot;&gt;&lt;/div&gt;&lt;div title=&quot;😈 Lawful Evil&quot;&gt;&lt;style data-emotion=&quot;css 12cl6bp&quot;&gt;.css-12cl6bp{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-flex:1;-ms-flex:1;flex:1;}&lt;/style&gt;&lt;div class=&quot;css-12cl6bp&quot;&gt;&lt;style data-emotion=&quot;css 7f8ji2&quot;&gt;.css-7f8ji2{font-family:var(--chakra-fonts-heading);font-weight:var(--chakra-fontWeights-bold);font-size:var(--chakra-fontSizes-3xl);line-height:1.33;color:var(--chakra-colors-text-300);}@media screen and (min-width: 48em){.css-7f8ji2{font-size:var(--chakra-fontSizes-4xl);line-height:1.2;}}&lt;/style&gt;&lt;h2 class=&quot;chakra-heading css-7f8ji2&quot;&gt;?&lt;/h2&gt;&lt;/div&gt;&lt;/div&gt;&lt;div title=&quot;😈 Neutral Evil&quot; subtitle=&quot;Botting as a service&quot; options=&quot;GPU Scalpers,Sneakerbots,Votebots,Automated account cracking&quot;&gt;&lt;/div&gt;&lt;div title=&quot;😈 Chaotic Evil&quot; subtitle=&quot;Purely malicious hacking and/or service denial&quot; options=&quot;DDOS,Destructionware&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;h3 id=&quot;-lawful-good&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-lawful-good&quot;&gt;😇 Lawful Good&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The good guys.&lt;/p&gt;&lt;p&gt;Any automation that is beneficial to you and conforms to how you expect it to behave with pure intentions. These are generally your standard search engines. They’re the reason why the internet works in the first place. Aside from a few ridiculous crawlers like &lt;code&gt;Baidubot&lt;/code&gt;, they will go out of their way to ensure your site isn’t affected by what they’re doing.&lt;/p&gt;&lt;p&gt;They’re also the reason why it can be challenging to protect yourself against unwanted automation. Sometimes a good solution for blocking bad bots you don’t want might need to be reconsidered if it also blocks the “good bots” which would ultimately be a net negative for your site.&lt;/p&gt;&lt;h3 id=&quot;-neutral-good&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-neutral-good&quot;&gt;😇 Neutral Good&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The &lt;/p&gt;&lt;div color=&quot;blue.400&quot; text=&quot;blue team&quot;&gt;Blue team in computer security refers to the party that is on the defending side of a system that is being attacked.&lt;/div&gt;.&lt;p&gt;&lt;/p&gt;&lt;p&gt;These companies/services will ensure that &lt;/p&gt;&lt;div&gt;Neutral Evil&lt;/div&gt; does not manage to automate your website and cause harm. They fight for good, but the methods that they use to provide their services result in privacy violations for real users through the use of things like browser fingerprinting and aggressive data collection.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Protection like Google’s ReCaptcha or Binance’s weird puzzle slider thingy also often make it difficult and sometimes impossible for a lot of users who rely on accessibility tools like screen readers to continue using the site.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:375px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/8c7754b6f09a42af8ba99d94cc9d8413/5ff7e/slider.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:90.8%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAIAAADUsmlHAAAACXBIWXMAAAsTAAALEwEAmpwYAAADE0lEQVQ4y22T709SURjH/X9q9abVnM3aStsspZAL3N9c4J4TvawXreZ60Yu2lpQaGmgXdOWKqTPlcrnXaGqmTWu1TCcpRsAFRUMMm9gVdxu0LKjvnp3zfbbzOd9nOzsVbLkgCyALLhZXWGx/efDPSbZi3wHAQggBo2epesDogKmRZfSF1qQFDAIYBILyG/7AZrOZYiCF6wnjWRI9T6IaEtMWCq2nMC2F62gGMGZLOQwAoGm6+c7tN+NPJ8SuScn9SvJMPfdMPe+eHPFMjvRMSJ4JkZsZfcx1dZhMDPg9QAGGEBA008O1RyRqrP3wdHfVTHfVmPPYuKvybc/x6e7qL35thD+XGtWLgw8pk3V/+AoWAGi14BcaXQ/uzQ0R/uZD467jYuuRsV4s9OKK4/rRa8xBydWwzGujIjLk7UAxCpbBxHltl7MlxFP8nQNjzsrh5sMSV/vOR7tvVtqvnpr2NUUEfVwqwEaU/Asujk3SDNfZJo+C973Vs97aWW/NB+/pj301C4MNsde3Npb6o+OX4yMI399Jl4zNshAAkjJxnfdXXtoWB8+EfZrwcH3Yp1kaOrcsoOuzzkx4QJ6+lRi1+Ac4iraAsmScoJztdvkFOf/kWKj/RKivOtR38tNATZhvTEzdSC88igQvyUHc1+ciKXMZDFEMd7TdzcWHVz441+bca3Pc+kdPev5RerF/MyJkPvPppeHt2JDo8xIkDUufCuI4zrnd33N78ZVMcu3b6vrWppJN725sbGzLq+lkKhNPfs1u50VRwnEcQliajKIOh2Nraysai8aTciKRTGXkZCaSWk3F5Hg8IX+JRTObm6IokST5H9jlcqmqurOzoyhKPp9XfijKjrK7u5svSlEUVVUFQTAYDCWwzWZr0GhaWltzuVw2m83lcuo/2tvbU1V18Nmzuro6m81WkoxhWFNTkyRJPM/zfj4QCAhCQPitQCDg9/uDwaDdbjcajSXJBVkYhjKSGEJiOhLTUSROEIS+IAOCIIaiw4w6E4GwFtN/viTLWiEEhQIAFvVnL6rgWKvVat2HfwIy9ksEvj3BxQAAAABJRU5ErkJggg==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/8c7754b6f09a42af8ba99d94cc9d8413/490da/slider.webp 250w,/static/8c7754b6f09a42af8ba99d94cc9d8413/3c596/slider.webp 375w&quot; sizes=&quot;(max-width: 375px) 100vw, 375px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/8c7754b6f09a42af8ba99d94cc9d8413/63868/slider.png 250w,/static/8c7754b6f09a42af8ba99d94cc9d8413/5ff7e/slider.png 375w&quot; sizes=&quot;(max-width: 375px) 100vw, 375px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/8c7754b6f09a42af8ba99d94cc9d8413/5ff7e/slider.png&quot; alt=&quot;binance&apos;s slider puzzle for logins&quot; title=&quot;binance&apos;s slider puzzle for logins&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Bots are very hard to distinguish from users who use the same technologies for legitimate purposes. If you want to make things harder for bots, you inevitably make things harder for accessibility tools, and any bypass you add to help these users will be abused by bots who pretend to be legitimate users requiring accessibility. This often puts fighters in this category in a very tricky position of lose-lose where there’s just no good solution to the problem that doesn’t involve major compromises.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div&gt;Neutral Good&lt;/div&gt; is in a constant battle with &lt;div&gt;Neutral Evil&lt;/div&gt; as well as regular users who feel like they&apos;ve become collateral damage in the name of web security and have come to expect it to work like magic without involving any drawbacks.&lt;/div&gt;&lt;h3 id=&quot;-chaotic-good&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-chaotic-good&quot;&gt;😇 Chaotic Good&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The kinds of automation that are ultimately for the benefit of everyone but have to be exercised with caution.&lt;/p&gt;&lt;p&gt;One of the best examples of this is probably &lt;/p&gt;&lt;div href=&quot;https://shodan.io&quot;&gt;Shodan.io&lt;/div&gt;. They are constantly scanning your infrastructure and exposing the tools running on it like databases, SSH access, FTP servers, and more. If you use it properly, it’s a tool that can be used to detect unwanted exposure, but it’s also a tool that allows bad actors to uncover information about your infrastructure that could’ve
otherwise stayed hidden.&lt;p&gt;&lt;/p&gt;&lt;p&gt;It’s not a good practice to rely on &lt;/p&gt;&lt;div color=&quot;teal.400&quot; text=&quot;security through obscurity&quot;&gt;The practice of trying to secure access to important data by making things confusing and relying on the incompetency of a 3rd party rather than actually securing the access required for it.&lt;br&gt;&lt;br&gt;For example: hiding the key to your house under your doormat, hoping nobody finds it, instead of keeping it somewhere that&apos;s actually secure.&lt;/div&gt;, but there’s definitely an argument to be made for how Shodan can be abused for the same reasons it can be a useful protection tool.&lt;p&gt;&lt;/p&gt;&lt;h3 id=&quot;-lawful-neutral&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-lawful-neutral&quot;&gt;🙄 Lawful Neutral&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Overall useful utilities with no specific benevolent or malevolent purpose.&lt;/p&gt;&lt;p&gt;IoT devices in specific have no specific alignment other than doing what they need to be doing, which is generally positive. They don’t provide a service in general that can be considered inherently malicious or benevolent.&lt;/p&gt;&lt;h3 id=&quot;-true-neutral&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-true-neutral&quot;&gt;🙄 True Neutral&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Mostly uninvolved 3rd parties.&lt;/p&gt;&lt;p&gt;These people aren’t really motivated in any particular way. They just want to go about their day without having to deal with a bunch of stuff. This is usually people who are just trying to create something new for the sake of learning or for fun, and often get caught in the crossfire between abuse and protection.&lt;/p&gt;&lt;h3 id=&quot;-chaotic-neutral&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-chaotic-neutral&quot;&gt;🙄 Chaotic Neutral&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The services who provide ammunition for everyone else.&lt;/p&gt;&lt;p&gt;There’s a huge part of the bot ecosystem built around vendors that sell different kinds of tooling that can be purchased to execute abuse at a bigger scale. The most common examples of these are services like &lt;/p&gt;&lt;div href=&quot;https://brightdata.com/&quot;&gt;Luminati&lt;/div&gt; (I guess they call themselves Bright Data now) or &lt;div href=&quot;https://oxylabs.io/&quot;&gt;Oxylabs&lt;/div&gt; which will sell you proxies that “lend” you their IP address which can be used to bypass anti-abuse measures like IP bans.&lt;p&gt;&lt;/p&gt;&lt;p&gt;There are other ones like &lt;/p&gt;&lt;div href=&quot;https://2captcha.com/&quot;&gt;2Captcha&lt;/div&gt; where you can pay a child in Bangladesh 3 cents to click on fire hydrants in captchas for you so you can deploy an army of automated bots to get past human checks. This is why captchas are borderline useless on sites targeted by botters who have the money to pay for these kinds of 3rd party captcha services.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Similar to selling guns on the black market to unknown buyers, &lt;/p&gt;&lt;div&gt;Chaotic Neutral&lt;/div&gt; doesn’t &lt;em&gt;technically&lt;/em&gt; carry out any of the abuse themselves, instead enables another party to do it in exchange for money. The morality here is questionable at best, and they’re well aware of what their target market is.&lt;p&gt;&lt;/p&gt;&lt;h3 id=&quot;-lawful-evil&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-lawful-evil&quot;&gt;😈 Lawful Evil&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;I don’t actually know what fits into this category.&lt;/p&gt;&lt;p&gt;Any technology or service that is malicious enough to cause problems is motivated by money or something equally as selfish. I can’t think of any sort of destructive automation in the wild that claims to be self-righteous to justify its actions. The first thing that comes to mind is something like &lt;/p&gt;&lt;div&gt;Anonymous&lt;/div&gt;, but they don’t fit into the category of automation.&lt;p&gt;&lt;/p&gt;&lt;h3 id=&quot;-neutral-evil&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-neutral-evil&quot;&gt;😈 Neutral Evil&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The &lt;/p&gt;&lt;div color=&quot;red.400&quot; text=&quot;red team&quot;&gt;The red team (in contrast to the blue team) is used to refer to the attacking side in computer security.&lt;/div&gt;.&lt;p&gt;&lt;/p&gt;&lt;p&gt;People using automation in this category do not have malicious intentions or want to cause harm to the services they target. However, they believe that they have the right to obtain what they want without any regard for rules and do not care about whether or not their actions will harm the other party involved.&lt;/p&gt;&lt;p&gt;This is the category of bots that cause the price of GPUs to skyrocket, get your Roblox account hacked, purchase the limited edition Supreme crowbar you wanted, and add millions of fake views to videos on YouTube.&lt;/p&gt;&lt;p&gt;The industry behind these bots has grown to such a scale that most people have started considering it a fact of life. Speaking of sneakerbots and scalpers in specific, they’re sold as a service to users who want to run their own bots to buy limited edition stuff and have a rich support system backing up their customers. They’re run by dedicated developers who charge a subscription fee and always stay up to date with the latest changes to sites to make sure users of the bot can continue to bypass new protections.&lt;/p&gt;&lt;p&gt;For people at the top tiers of this category, it’s not a matter of &lt;em&gt;whether&lt;/em&gt; you’ll be able to stop them, but for how long. When the person abusing your site makes a million dollars a year offering their services, there’s not a whole lot you can throw their way to tire them out.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div&gt;Neutral Evil&lt;/div&gt; generally believes that they&apos;re not doing anything wrong; instead, they think they&apos;re simply hustling and that it&apos;s up to everyone else to step up their game instead of being forced to stop.&lt;/div&gt;&lt;p&gt;Despite not being motivated by malice in specific, they’re ready to go to similar extents as &lt;/p&gt;&lt;div&gt;Chaotic Evil&lt;/div&gt; to get what they want.&lt;p&gt;&lt;/p&gt;&lt;h3 id=&quot;-chaotic-evil&quot;&gt;&lt;a href=&quot;https://xetera.dev/#-chaotic-evil&quot;&gt;😈 Chaotic Evil&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The bad guys.&lt;/p&gt;&lt;p&gt;These are the actors whose actions center around bringing harm to the services they target. Whether it’s caused by revenge or something else, the automation in this field primarily serves to inflict damage to the victim without an obvious direct benefit to the actor. This mostly includes things like botnet DDoS or destructionware.&lt;/p&gt;&lt;p&gt;Surprisingly, there’s not a whole lot that falls into this category. Unlike anime supervillains, most people in real life are not motivated by pure evil; there’s almost always an underlying motivation that explains people’s actions beyond just being evil and wanting world domination.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;I’m a huge fan of this little world we’ve built around automation and the endless cat and mouse game between the two parties. Hopefully, I’ll have the opportunity to work more in-depth in this field and learn more about different kinds of ways to keep raising the bar of competency needed from bot developers to abuse services.&lt;/p&gt;&lt;div title=&quot;For The Record&quot; icon=&quot;[object Object]&quot;&gt;&lt;style data-emotion=&quot;css 19lix1a&quot;&gt;.css-19lix1a{color:var(--chakra-colors-text-300);text-align:left;-webkit-align-self:flex-start;-ms-flex-item-align:flex-start;align-self:flex-start;}&lt;/style&gt;&lt;p class=&quot;chakra-text css-19lix1a&quot;&gt;I&apos;ve never actually played dungeons &amp;amp; dragons so if the reasoning behind where I put things in my alignment chart seems off then uh... I don&apos;t really care, sorry nerds.&lt;/p&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[❄️ Blizzard's Downfall]]></title><link>https://xetera.dev/blizzards-downfall/</link><guid isPermaLink="false">https://xetera.dev/blizzards-downfall/</guid><pubDate>Sun, 01 Aug 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/blizzards-downfall/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;In 2017 I moved to California to live with my mom and go to one of the nearby community colleges to study computer science. One of the things I couldn’t stop thinking about when I got there was the fact that my mom lived 10 minutes away from the Blizzard Headquarters in Irvine.&lt;/p&gt;&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom:75%;position:relative;height:0;overflow:hidden;margin-bottom:1.0725rem&quot;&gt; &lt;iframe src=&quot;https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d106287.6497335395!2d-117.82212765814606!3d33.644487858766404!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x80dcde82907fe8bb%3A0xcb7104743d635730!2sBlizzard%20Entertainment!5e0!3m2!1sen!2sus!4v1627808390530!5m2!1sen!2sus&quot; style=&quot;border:0;position:absolute;top:0;left:0;width:100%;height:100%&quot; allowfullscreen=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/iframe&gt; &lt;/div&gt;&lt;p&gt;It felt surreal, but when I checked the map for the first time, it was there in all of its glory, no cap. All fax no printer. The company that makes the game I’ve been obsessed with for years as a kid, standing a very exhausting jogging distance away from the bed I go to sleep on every day.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:406px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/5a8b3dc5ec60cbdb60b2e25fb04f47bf/e33ef/blizzard_route.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:147.2%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAdCAIAAAAl5NuSAAAACXBIWXMAAAsTAAALEwEAmpwYAAADzElEQVQ4y4VSW08bRxTe9wb1rRivgQSMuQUn5KZEUfvUvgf1qWm4RFVfG+y1G3zDgJWoaUD9NXWltJHzC7D7UrUCUdjFc/G63pv34vXubDVe4xJjmk+fRmd3zjdzzjeHYTnw+Z44uQE//aG2sAm/2Nz/LLV/r1B7+LI2k4HRPJrJwAcvcCgB5rKIjYOROIik4Z0CDsQAw3IgnEKjCRDegKMJOMv9GYn/NbGBIik4mgBjSXD1ezidhqEEuPYcshwIcmA8CSafw2AcMMF4R5ake/M5RGVpqgyn4HQaTKWoeDgGWI7eyXLd4JP1aogDzEgc3MijsSSYSsHbOzi6iRa30I08Wtj0VxhJwxAHRhMglKAry9Gyo5uIlj0SB3d28HgSTGfQ9RyazVLZ9Ryaz9F1JgNns+jmFo2jebSQR0GO1hjNo5E4YAIxcK+Ax5NwLgvvFnA0jxa30c0tfHsHL27jzuX4bgHf2kaLW/jWNh5L0rIDsSrLASbEgQcv8FQK0svTaDpN7QmnqB9+h30MnVuZUALef1kLp6lV8zk8k8VzORzJIDYBP0iGjfHD3/HBdX5knQbDz/jAMxqzscH0M/0Ehl0uhVZK7HJpbPXd1aeUY2vdPwM5vvbuWieNXS4xQ0vFK0vFjx79HPjqzcTa24nV34KP33z85S9DS0V/a+gcrzwqjj75dfbb0uTTt0NLRWZ5t/zNT+W1vfLKa8rl1+XV3fLaXqXH1b3Kym65xyc/lh+/2v/61f7KbpnxPK8qe4btucSzHK/terbjOYR+tonXcml8Gaj4d4HIhqea7mnDQbIDZQcrjqg5QKasay7xvPdIPEII8Tym1aYnE+J/9uEs+X109whhNJOcCrxpmqZlYVwTxbokyfX6Pwhhy7IuluoSt2EokqnSspsWOTn52zQtVVWPj0+E01MIIUJIEARJklqtVt8Rtm1jWUSy2BWf/bWammyZhqZpzWbTMAxFURqNhqIo58W6rmuKqmt6T0z1NY38AV2oXG7uRbd74lbbbVqOZbuEENd1LzrU88lPoGLX7fp5Zq/Xp+yDv9t1mxBSqVQ0TZNl+fj4+OjoSBCEw8ND36eL7+cSF6i1UwV1h8S2bf9Ix3Ha7bbruv46sE/DMBqSJMlSVzwQAwfDb6rdARX3Ghg0YYNP/G/CCCEHBwd6B4IgVDuAEIqiWK1WeZ7HHfA8L3ce3LBNqNXr+lnZCCF/kqQOfPNkWVZV1R8SVVUVRdF1Ohi6oWNJFOX6//V8GSzLMg3DMulbMLZtt1otu4PWh2DbNvXKaTuOY9v2vyGCQcC4XphaAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/5a8b3dc5ec60cbdb60b2e25fb04f47bf/490da/blizzard_route.webp 250w,/static/5a8b3dc5ec60cbdb60b2e25fb04f47bf/79985/blizzard_route.webp 406w&quot; sizes=&quot;(max-width: 406px) 100vw, 406px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/5a8b3dc5ec60cbdb60b2e25fb04f47bf/63868/blizzard_route.png 250w,/static/5a8b3dc5ec60cbdb60b2e25fb04f47bf/e33ef/blizzard_route.png 406w&quot; sizes=&quot;(max-width: 406px) 100vw, 406px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/5a8b3dc5ec60cbdb60b2e25fb04f47bf/e33ef/blizzard_route.png&quot; alt=&quot;blizzard route&quot; title=&quot;blizzard route&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Because I had only just gotten into programming at the time, I couldn’t even fathom the idea of trying to get in contact with someone working there or applying for a position/internship. So for the next three years, I went past the Blizzard HQ every day on my way to school, wishing they’d just give me a chance.&lt;/p&gt;&lt;p&gt;At the end of 2019, I finally managed to build up a somewhat decent resume of projects and got the courage to apply for an internship. I had a lot of the skills that were required in the listing so I felt like I had a chance at the time.&lt;/p&gt;&lt;p&gt;A couple of weeks after I applied, I went for lunch by myself at one of the Japanese restaurants near their HQ, and I saw like 10 Blizzard employees with badges walk in for their lunch break which I thought was &lt;/p&gt;&lt;div&gt;incredibly&lt;/div&gt; cool and freaked out for a bit. After what felt like an hour of contemplation, I finally got the courage to say hi to a girl who was waiting for her food at the table next to me. We talked for a little while, and I found out that she works on Overwatch as a character design person and —unsurprisingly— enjoys what she does. She also wished me luck when I told her I applied for an internship and that I was waiting for a response. I had to cut it short after this because I was obviously bothering her, and she just wanted me to stop talking. Or at least that’s what my brain kept telling me, as it always does whenever I want to chat with strangers.&lt;p&gt;&lt;/p&gt;&lt;p&gt;To put this into perspective, I have &lt;/p&gt;&lt;div&gt;really&lt;/div&gt; bad social anxiety when it comes to interacting with people IRL so this was one of the few instances where I managed to get myself to talk to another person without being forced to in my 3-4 years being in the US.&lt;p&gt;&lt;/p&gt;&lt;p&gt;But of course, as with every big company, they get many applications; hundreds of people get rejected every time, and I was one of them. They also took over &lt;/p&gt;&lt;div&gt;6 months&lt;/div&gt; to get back to me, which I thought was funny.&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:827px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/99673beb051bfea080e7286ec3bbfce6/4e6ec/rejection_letter.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:84.8%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABs0lEQVQ4y42T25KbMAyGef9nbEMBA7aJwWcb+ZAdrGwmbafb/S4YgfRbJ9xJIVYyz+NExnEmZCJz/2scx2kYxmGYhpGQeR2n+eetZ3xzPlrrjHXLSlfKOq31re9vt34iszaGrtQ5F2Pw3oUQnLMxBO+9tQYAHo1aa4KUADqlFCEzpYxSdr/fOedSyhij9x4Aaq0oyLmEEGOMIQRolFI6H4KUqp3tbMO5K2dosed5Yuh5nvGNEMJ5nl1KCePyJ+lLACCllHP23l/iltb+S/aKxlc0SikAcImNMUKIfd+3bRNCcM4ppYyxbdsopfwT1kAb27nEWutlXWmDc77vu5TyOA6lFB56NF6G1hpH0EFK3jklD6OlVlJK+fds/uDl6nJOYlc/BtaT+7hsWBhWsSwLpXRtYCPoNcbgIq6ylba7itoXGxLAiY73/GjjetDIOT97VkpyTu8b2zjDDJgcGxZCHMeBT+xcCIHJL7G1tk1Ivg8mhJBSqrWW38EvtdarbADw3kspnXOllNcyH//j2bPWGpdkjHl8m6dYCLEsy/tIlVKhXaYvsNbiwNp+pVRKvX4D+w0+ANxOzCXPoEOgAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/99673beb051bfea080e7286ec3bbfce6/490da/rejection_letter.webp 250w,/static/99673beb051bfea080e7286ec3bbfce6/e333e/rejection_letter.webp 500w,/static/99673beb051bfea080e7286ec3bbfce6/c346a/rejection_letter.webp 827w&quot; sizes=&quot;(max-width: 827px) 100vw, 827px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/99673beb051bfea080e7286ec3bbfce6/63868/rejection_letter.png 250w,/static/99673beb051bfea080e7286ec3bbfce6/0b533/rejection_letter.png 500w,/static/99673beb051bfea080e7286ec3bbfce6/4e6ec/rejection_letter.png 827w&quot; sizes=&quot;(max-width: 827px) 100vw, 827px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/99673beb051bfea080e7286ec3bbfce6/4e6ec/rejection_letter.png&quot; alt=&quot;rejection letter&quot; title=&quot;rejection letter&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;The rejection hurt at the time. I had stopped playing games and World of Warcraft for a while, so it’s not like I wanted to work on WoW in specific, but this was my dream since coming to the US.&lt;/p&gt;&lt;h2 id=&quot;the-gaming-industry&quot;&gt;&lt;a href=&quot;https://xetera.dev/#the-gaming-industry&quot;&gt;The gaming industry&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;One of the reasons why it was harder for me is because Blizzard is no ordinary company. I wasn’t competing against people who wanted a job to make money; I was competing against people whose dream was also to work at Blizzard.&lt;/p&gt;&lt;p&gt;This is one of the incredible benefits of being a game company. There are so many people out there who’s only dream is to share the incredible experiences they’ve had playing games with the rest of the world, and enable others to feel the same kind of joy they did playing games as a kid (or still do as adults in many cases). I don’t know a whole lot of people who find the same kind of purpose in working on health insurance software.&lt;/p&gt;&lt;p&gt;Because of this, the people who are currently working at big game companies like Blizzard and Riot Games are mostly interested in keeping their positions working on the games they love before anything else. They’re significantly less likely to complain about the routine unpaid overtime. They’re not interested in raising hell over injustice. They’re prepared to take on a sea of L’s because a lot of them have conditioned themselves to believe that they’ve been blessed by the miracle of working at an amazing game company like Blizzard and that they have to shut up and take the good parts with the bad because that’s just how things are.&lt;/p&gt;&lt;p&gt;Despite this disincentive to speak up, Blizzard has finally found themselves &lt;a href=&quot;https://time.com/6086010/activision-blizzard-california-lawsuit-sexual-harassment/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;buried neck-deep in lawsuits over mistreatment&lt;/a&gt;. They’ve managed to drive a group of people who will suck it up and take whatever is thrown at them to the edge to finally say something.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:800px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/6de6cab154170f689fb1325c51d57142/4b190/walkout.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:75.2%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAf/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAFydXERSJ//xAAaEAADAQADAAAAAAAAAAAAAAABAgMAEiIx/9oACAEBAAEFAvEp2lxwRxjN80GY/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQL/2gAIAQMBAT8Biaf/xAAWEQEBAQAAAAAAAAAAAAAAAAAAESL/2gAIAQIBAT8BrL//xAAdEAABAgcAAAAAAAAAAAAAAAAAARECITEyQYGh/9oACAEBAAY/AlaHgmC4qSbY5//EABoQAQADAQEBAAAAAAAAAAAAAAEAESFhcVH/2gAIAQEAAT8hHQW4XTZqiH02X+JxnsqmlQlSb2f/2gAMAwEAAgADAAAAEAcv/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAFRof/aAAgBAwEBPxBl0w//xAAXEQADAQAAAAAAAAAAAAAAAAAAAVGh/9oACAECAQE/EFYnOn//xAAeEAEAAgICAwEAAAAAAAAAAAABABEhQTFRcbHB0f/aAAgBAQABPxBjqVQE0xxFvMZIZyVEapu71ME4Ne0pC1unf7GbnwfJ/9k=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/6de6cab154170f689fb1325c51d57142/490da/walkout.webp 250w,/static/6de6cab154170f689fb1325c51d57142/e333e/walkout.webp 500w,/static/6de6cab154170f689fb1325c51d57142/01aab/walkout.webp 800w&quot; sizes=&quot;(max-width: 800px) 100vw, 800px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/6de6cab154170f689fb1325c51d57142/0479a/walkout.jpg 250w,/static/6de6cab154170f689fb1325c51d57142/41099/walkout.jpg 500w,/static/6de6cab154170f689fb1325c51d57142/4b190/walkout.jpg 800w&quot; sizes=&quot;(max-width: 800px) 100vw, 800px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/6de6cab154170f689fb1325c51d57142/4b190/walkout.jpg&quot; alt=&quot;walkout&quot; title=&quot;walkout&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;div as=&quot;figcaption&quot; textalign=&quot;center&quot; mb=&quot;6&quot; color=&quot;text.400&quot; font-size=&quot;sm,,md&quot;&gt;Blizzard employees staging a walkout on the same street I used to drive on going to school every day.&lt;/div&gt;&lt;p&gt;Imagine how bad it must have been for it to get to this point. Of course, if you’ve been following along with the gaming industry, either as a gamer or a game developer yourself, you don’t have to imagine anything. You already knew that this was something that’s been going on for years and probably had to tell yourself that &lt;/p&gt;&lt;div&gt;it’s just how things are&lt;/div&gt; to be able to turn a blind eye to everything going on and to keep enjoying the games you love playing. Gaming is supposed to be chill and not like other jobs. So what if &lt;a href=&quot;https://kotaku.com/top-riot-executive-suspended-without-pay-following-inve-1831084598&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;the company COO is farting on your coworkers’ faces and touching them inappropriately&lt;/a&gt;? So what if your company recruiters are &lt;a href=&quot;https://twitter.com/jmgosney/status/839727489635209216?s=20&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;asking female security experts if they like being penetrated&lt;/a&gt; at conferences? They’re just like… having fun man, maybe women need to stop being so angry all the time, right?&lt;p&gt;&lt;/p&gt;&lt;p&gt;As much as it pains me to say this, the reason why Blizzard might finally be facing the consequences now isn’t because they’ve fostered a hostile work environment for women for years by hiring bigoted, misogynistic men. It’s because they hired &lt;/p&gt;&lt;div&gt;stupid&lt;/div&gt; bigoted and misogynistic men who are not only bad at their job but bad at being a bigot too.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Here’s a quote from &lt;a href=&quot;https://www.npr.org/2021/07/22/1019293032/activision-blizzard-lawsuit-unequal-pay-sexual-harassment-video-games&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;NPR&lt;/a&gt; about the blizzard scandal.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;One woman said her manager told her she wouldn’t be promoted because “she might get pregnant and like being a mom too much.”&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Now, I’m not a manager myself, so I don’t know the details of these kinds of things inside out, but I’m pretty sure you cannot say something like this. Not just morally, but as a part of your job, you cannot say these kinds of things to your employees because you’re becoming a liability and (little did he know) opening the company up for a lawsuit. There are plenty of male managers out there in the gaming industry who have a relentless hatred for women who manage to keep their positions because they know what they can and can’t say as a part of their job. They’re shitty people, but they are somewhat decent managers and get to live off the “isn’t it so great to do the thing you love for a living” debuff women get hit with dealing with them every day.&lt;/p&gt;&lt;p&gt;In Blizzard’s case, it seems like the people in charge still think they’re in a college frat house and don’t have any idea what they’re doing, even when it comes to their job. You can imagine incompetency of this degree probably contributed significantly to the decline of World of Warcraft. It seems like your skills at drinking games in the office and harassing women is a more important factor in your value at Blizzard than the kind of work you do.&lt;/p&gt;&lt;p&gt;In most cases, intolerant people of all types learn that they need to keep quiet about their views early on. They understand what is socially acceptable and what isn’t and will only open up about their views to others once they realize that the other person is equally as intolerant about the same things.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:880px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/0891cc90d4667745839fc9ffd40fdcdd/f84cf/skyrim.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:54.400000000000006%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIEAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAACA//aAAwDAQACEAMQAAAByh6MRCDlj//EABsQAAEEAwAAAAAAAAAAAAAAAAEAAhESAzJC/9oACAEBAAEFAsbRFBYhoXT9yIX/xAAVEQEBAAAAAAAAAAAAAAAAAAAQMf/aAAgBAwEBPwGn/8QAFxEAAwEAAAAAAAAAAAAAAAAAAQIQIf/aAAgBAgEBPwFcM//EABgQAQEAAwAAAAAAAAAAAAAAAAEQABFB/9oACAEBAAY/AkTmO6z/xAAYEAEBAQEBAAAAAAAAAAAAAAABEQAhQf/aAAgBAQABPyFEk5AohlJzCiPN1goh5v/aAAwDAQACAAMAAAAQRA//xAAYEQACAwAAAAAAAAAAAAAAAAAAEQEhMf/aAAgBAwEBPxBIZUn/xAAWEQEBAQAAAAAAAAAAAAAAAAAAETH/2gAIAQIBAT8QujX/xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhQTFx/9oACAEBAAE/EE+KjTrBkLokqKh6WQTuBx2Es7saJAlfs//Z&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/0891cc90d4667745839fc9ffd40fdcdd/490da/skyrim.webp 250w,/static/0891cc90d4667745839fc9ffd40fdcdd/e333e/skyrim.webp 500w,/static/0891cc90d4667745839fc9ffd40fdcdd/11898/skyrim.webp 880w&quot; sizes=&quot;(max-width: 880px) 100vw, 880px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/0891cc90d4667745839fc9ffd40fdcdd/0479a/skyrim.jpg 250w,/static/0891cc90d4667745839fc9ffd40fdcdd/41099/skyrim.jpg 500w,/static/0891cc90d4667745839fc9ffd40fdcdd/f84cf/skyrim.jpg 880w&quot; sizes=&quot;(max-width: 880px) 100vw, 880px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/0891cc90d4667745839fc9ffd40fdcdd/f84cf/skyrim.jpg&quot; alt=&quot;skyrim&quot; title=&quot;skyrim&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Managers at Blizzard don’t seem to understand this basic idea either. And it’s only because of this gross incompetency that we’re finally hearing something about mistreatment from the public and following along with a lawsuit. Who knows how much longer they could’ve kept this going if they simply played into the industry standard of sexual harassment without crossing into the &lt;/p&gt;&lt;div&gt;blatant&lt;/div&gt; sexual harassment category.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Looking back now, I have to thank the university relations team at Blizzard for turning down my internship application because it allowed me to start my position at Top.gg in the summer of 2020.&lt;/p&gt;&lt;p&gt;You cannot have a positive work environment that is rooted in institutional gender discrimination, harassment, and a lack of accountability. You also cannot have a positive work environment where your privileged superiors see you as an amorphous blob of an employee and &lt;a href=&quot;https://world.hey.com/jason/changes-at-basecamp-7f32afc5&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;don’t think you should be allowed to talk about problems that affect your life when you’re at work&lt;/a&gt;. People tend to be their best selves in environments where they feel respected and don’t have to worry about being treated differently because of who they are because you &lt;/p&gt;&lt;div&gt;don’t&lt;/div&gt; stop being a unique individual when you sign a contract.&lt;p&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🚫 India banned my site... I think?]]></title><link>https://xetera.dev/india-banned-my-site/</link><guid isPermaLink="false">https://xetera.dev/india-banned-my-site/</guid><pubDate>Sat, 03 Jul 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/india-banned-my-site/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;A few days ago I got a ping from one of the moderators in the Top.gg Discord server about something I’ve never seen happen before.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div messages=&quot;[object Object],might wanna check this one out,one of the users is having problems with it&quot; date=&quot;like probably 5 minutes ago&quot; username=&quot;marco_rennmaus | Rennmoose2&quot; rolecolor=&quot;red.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;I’m sorry? Why would a documentation site get banned by the Indian government? Surely this is a mistake. Anyways, best to check it out to see what’s going on.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div messages=&quot;[object Object],any reason why?,you have some expired license for that URL or something?&quot; username=&quot;Maverick Wolf&quot; rolecolor=&quot;green.300&quot; date=&quot;06/28/2021&quot; avatar=&quot;static/maverick-wolf-fc7e9395cf7bd12854bd112f551a438a.png&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;lemme check with a VPN,huh, weird,[object Object],could be getting caught in a wide net cast on some subdomains&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;well uhm,how to fix kekw&quot; date=&quot;06/28/2021&quot; username=&quot;marco_rennmaus | Rennmoose2&quot; rolecolor=&quot;red.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;apparently some indian isps briefly banned google docs in 2014,could be some sort of clash with that?,docs.google.com, docs.top.gg&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Ok, this is a strange situation but the google docs ban seems like a fairly reasonable lead to follow.&lt;/p&gt;&lt;p&gt;After a little bit of digging around on Google I found out that Google sites were never blocked to begin with.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;In an order dated 23 June 2014, the Delhi High Court upon a request made by Sony Entertainment ordered 472 file sharing and file hosting websites blocked, including The Pirate Bay, Google Docs, Google Videos, and Google’s URL shorterner (goo.gl) […] However, it was reported on 7 July 2014 that an updated court order blocks just 219 sites. Included are many file storage and torrent websites, &lt;strong&gt;but no Google sites.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;So I guess that’s not it then. Time to start looking somewhere else. Should I just be getting in touch with the Department of Telecommunications at this point? I know plenty of Indian developers in different communities I hang out in, maybe they can help me figure out what’s going on.&lt;/p&gt;&lt;p&gt;I’m also not convinced this is a global ban. Sure, a documentation site doesn’t receive that much traffic but we have a lot of Indian users and someone would’ve either let us know about this ban a long time ago, or there would be more than one person with the same problem, right? It seems very odd that I’m only now hearing about this and only from a single user.&lt;/p&gt;&lt;p&gt;Let’s check in with people in a different server.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div messages=&quot;does anyone know how I can get in touch with department of telecommunications in india lol&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot; date=&quot;06/28/2021&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;any reason for that?&quot; date=&quot;06/28/2021&quot; username=&quot;windows user&quot; avatar=&quot;static/windows-user-cc89d6254f4b87c3a84cf68de7d0594f.png&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;one of the sites I work on is blocked by them and my indian users can&apos;t access the site,it&apos;s literally just api documentation. I have no idea why it would be blocked&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot; date=&quot;06/28/2021&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;That&apos;s the Indian government for you,You can always try writing an email to them&quot; date=&quot;06/28/2021&quot; username=&quot;windows user&quot; avatar=&quot;static/windows-user-cc89d6254f4b87c3a84cf68de7d0594f.png&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;That &lt;em&gt;would&lt;/em&gt; be nice but I don’t think they want me, or really anyone emailing them, ever.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/b7123b398c831658f29c965be2af4679/29114/dot-contact-us.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:50.4%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACE0lEQVQoz5WQ3UsUYRTG52+poLugm4gkuoroS1AiCpOipJZwCRItQcliMfIii7QgQgm6iLpKJSHoY20tivwazd3V3N1ZZ8aZcbbN2d3Mdeb9xayu1VV14OE9z+F5nvdwpPCcydCcybCSYVBO0DM4xKNXH3kcHqF/ZIa3iUUiKZtI0uKDmmE4bZVm/aNxBibmGEpliKRM3syofIp9QersDVFdX8+Jxou032jkbnuAq60nCV0/y71b5+nqOM3t5uN0tJwhEAzQ0hBkR2Ul1bUHOVJTyZ59uwleCVLX/YxLbe1I0b4mHlw4yv1rp3h9p5aehp08aa3g+c39RF+cY6T3AJHgNsKXKzi8fQvNVXsJVO2i+dhmmg5tIlSzlc62AN2hOp521SHl7BSZ2Ri2liAWl3n3/iULiXG+mrM4jkJWj2LPjpNVPhObnkBXpzGUGVLRMZLxMSwtzryaJj4a5mHfABK/VXHVRdcNFkybb04ewf/V9LyNJISH53kgBMvLyxiGQcbO4DgOnueW5r6Gdd0vuCWIdS6E4Mf3wtqGPiltWBRksy653BoXwjet4rpuCWVd+S33ZZ7L5/0NxcYPxWIRwzCxTAvLWsS0HEwzx9JSgUKhsBEqPLERVPb75Wv+uKFvmE+nUVUVVdXQ1CyWJcjn/+2GKysrSJqm4UPXdRRFQZ6QmZqaQpZlJidTJJMqZc3f4Gf8BLGjuwe4zR2YAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/b7123b398c831658f29c965be2af4679/490da/dot-contact-us.webp 250w,/static/b7123b398c831658f29c965be2af4679/e333e/dot-contact-us.webp 500w,/static/b7123b398c831658f29c965be2af4679/54609/dot-contact-us.webp 1000w,/static/b7123b398c831658f29c965be2af4679/de0ca/dot-contact-us.webp 1500w,/static/b7123b398c831658f29c965be2af4679/ed2e8/dot-contact-us.webp 1920w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/b7123b398c831658f29c965be2af4679/63868/dot-contact-us.png 250w,/static/b7123b398c831658f29c965be2af4679/0b533/dot-contact-us.png 500w,/static/b7123b398c831658f29c965be2af4679/00d43/dot-contact-us.png 1000w,/static/b7123b398c831658f29c965be2af4679/aa440/dot-contact-us.png 1500w,/static/b7123b398c831658f29c965be2af4679/29114/dot-contact-us.png 1920w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/b7123b398c831658f29c965be2af4679/00d43/dot-contact-us.png&quot; alt=&quot;dot contact us page&quot; title=&quot;dot contact us page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;At least I can definitely relate to not wanting emails.&lt;/p&gt;&lt;p&gt;Oh they do have their twitter page up there though. Seems a bit silly but I know my mom managed to figure out some problems with Cox in the US only after DMing them on Twitter so maybe that’ll work for me here too.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:594px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/85906aeb6592b22632cda7f48d0938cb/5fd3e/dot-twitter-dm.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:119.19999999999999%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAYCAYAAAD6S912AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAEwUlEQVQ4y3WVaWwUZRiAV7C1DS10uzPb7jE7u93t7s5e3bPdHnR7UKWSSsthMJEjXjFGE5IGfyCiQaEaj4B/NGIV4xEuhbYEFf+YGELUSBRCggJFBEXQiHRpdyuQx8xsD1vKjyff934z88z7fu/kG93Kh5/goae6aWrvYtH9q1i+6lFWrH6MUsmL0e5HnAFB9k0yFouOEKKvDp0Sm48Sb8TiiWHzJTC5qhAdAcoqggiyH4PNh17yanOjIzBxbRzj/0ajK4yuxOpBb/VQYnEzz1ypjeOxTYnhCiXxJ1JI3piWjfqgfuwZDcmL6tCylH3oxsvwRhs01Iw9kQY8kXqqU+203LuUjuUriTcuJFDTTDDZot3njtTjDtfhCtXijc7XsleluvG9qAjUUBGswRlKIitxIvVtVNUuwBtrxBmqpWXRMupaO1DiKW3N4a/WsPsSOIPJMaF/MkO1CePorV5Euw/JG6WiqhbZH8cTq8cRTFDmVJvgoVSqnEAvuRDsHkS7khOq9umIcgjBFtYwSBEM1gSCVI1gq0aQazDaazVMjjqNcnsdRntksuQcfu0tqiQ/fwX5d66hIK+buXe9haX4AF7haxrMx+isOMMDnl9Z7DxL0nSCePlRHHO/RChZP1ly7vvKCQ3WOIUF6ygzbKbcsANn2SGa7Cfpjl+jJ3mDFxPX2RDN0h0aZrF8gYRwjIo5hzAUb5hB6PCityQR9R9Rm9hLTWyAjpbjrAhdYq07TU80y5Zoho2Ra6wLXWVN5UVqhKO4i75AKJ4xQw+CVEdRfh/FeV9RNPswQt5JIiW/sNRymbX2ITbJGXrkLM9XjPBkxd80CscIFB1Gmvf6VKEoB3LdsjUgzPkBQ+FvlOSfYN6s4zgKB2kTLvFI+RWeFtO8UJTh5cIsz84bpq34J4IFR5Dmbr1VKNrdCNJ8rKUnibj/Ilx5EZ/pD9zFf9JiuMLjpjQbxWtsLBjmJV2WLXdk6Jx9jtCsb7DOeW2mDN2IthTWknNUOUap9maodo4QLR+isTzNavMIzxlH2ZQ3yhbddTbr/mWZ7neqdN9jKnxlmlDdR7v6+YTwBB/EqaxEsHRgkjuxOjqxObpwOrrwyktQrF34LEtQLEtwWO7DbGmnzNY4Xegba46COxxFicWxehRkXwCTy02pJFNqs6OXp2KQHRrqdulmOuvUI8rkq8cWbsYebcUSSiG4qzG44hhcCYRp5NbjGCtj04UBRMmNEGzC/8aPRHvPEnr7NPHeM0TeGdTiaO+gNq/aPjgxT/SeIfDuBczPfD6D0FqJIdRC9INLtH12g9aBDM0DWZr6s6T6s4T3ZAjtyeDflSGwO0NwdwbXx8PYdt7E3PPd7YWJ9y/QfmCEe/qGWLA/Tev+NHf3pVk0kKNlXy5WSez6h/DeLPaeI7cXht87T9vACKlPrtK8b4i2PlWSk6uxKlrYnyb16RAL9l0l1T+KtPk2QqGqlciHl+k4pJacZeHBURr2Z/HuzFC1J0N4b25UUcv27xzGufsmpltL9iNKHgxKHcqr35LccY7Y9lPEtp/WmmPadoryrVNR10zbfsb65nks6w9OPxxyv0VRVhAq4whKHYK3dgKjMhXRm8QcakSKNGOLtmIONPAflLloRQ8ChugAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/85906aeb6592b22632cda7f48d0938cb/490da/dot-twitter-dm.webp 250w,/static/85906aeb6592b22632cda7f48d0938cb/e333e/dot-twitter-dm.webp 500w,/static/85906aeb6592b22632cda7f48d0938cb/f0891/dot-twitter-dm.webp 594w&quot; sizes=&quot;(max-width: 594px) 100vw, 594px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/85906aeb6592b22632cda7f48d0938cb/63868/dot-twitter-dm.png 250w,/static/85906aeb6592b22632cda7f48d0938cb/0b533/dot-twitter-dm.png 500w,/static/85906aeb6592b22632cda7f48d0938cb/5fd3e/dot-twitter-dm.png 594w&quot; sizes=&quot;(max-width: 594px) 100vw, 594px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/85906aeb6592b22632cda7f48d0938cb/5fd3e/dot-twitter-dm.png&quot; alt=&quot;dot twitter dms&quot; title=&quot;dot twitter dms&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;div font-size=&quot;sm&quot; mb=&quot;6&quot; textalign=&quot;center&quot; color=&quot;text.400&quot;&gt;Please ignore the fact that I yoinked the docs page from the &lt;div target=&quot;_blank&quot; href=&quot;https://www.apollographql.com/docs/&quot; rel=&quot;nofollower noopener&quot;&gt;apollo docs&lt;/div&gt;.&lt;/div&gt;&lt;p&gt;I know I don’t have a ton of experience sliding into DMs but I was really hoping the government of India of all people wouldn’t leave me on read.&lt;/p&gt;&lt;p&gt;They also have an option to leave feedback on their site. I could try sending the same message there.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:545px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/cb0ed888a557f6c10aae09ce733a2a20/3ddad/dot-contact-us-fail.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:30%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABA0lEQVQY052OTU/CUBBF+5ekJpI2wq5dQNzID9W4VNo+yrZ7xRhRMLTEyqJJP9577SEt4Mpo4p1M7py5mWQM8/yCXu8M0zQZXA6wbQvLshiPr5hMrhmNRriOi+M6DIeDLrNt++iH+cT9fh/j5vYOIQTedIrn+9w/TDuez0OECAjFDM/zjywIRIDv+4ThgT0v6PLZLCSKIowk+aSuG8qipJISpTRaa6SsyPMcJRVlWaGkRLa5Vp3rWqOUoqoUZVGhdU0rY7F4Ist2xNsN2yQhTVPizYaP9ZrVqVfvLJdvFEXBb2ofMV5eY7IMvnaKpq3m/w0NxuPzliSGONHd4u8jvv0n7QECXpvxLJlYvQAAAABJRU5ErkJggg==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/cb0ed888a557f6c10aae09ce733a2a20/490da/dot-contact-us-fail.webp 250w,/static/cb0ed888a557f6c10aae09ce733a2a20/e333e/dot-contact-us-fail.webp 500w,/static/cb0ed888a557f6c10aae09ce733a2a20/c5171/dot-contact-us-fail.webp 545w&quot; sizes=&quot;(max-width: 545px) 100vw, 545px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/cb0ed888a557f6c10aae09ce733a2a20/63868/dot-contact-us-fail.png 250w,/static/cb0ed888a557f6c10aae09ce733a2a20/0b533/dot-contact-us-fail.png 500w,/static/cb0ed888a557f6c10aae09ce733a2a20/3ddad/dot-contact-us-fail.png 545w&quot; sizes=&quot;(max-width: 545px) 100vw, 545px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/cb0ed888a557f6c10aae09ce733a2a20/3ddad/dot-contact-us-fail.png&quot; alt=&quot;failed contact us form submission&quot; title=&quot;failed contact us form submission&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Welp, that went about as well as I thought it would. I figured this might’ve been because of my non-indian IP but sadly it didn’t work with a VPN either. I dug around in dev tools and it’s something about my captcha being invalid…? I can’t even be bothered tbh.&lt;/p&gt;&lt;p&gt;It’s 10 AM at this point and I don’t exactly feel like making an international call inquiring the status of my national ban. Also, I hate phone calls, please don’t call me. It might be a good idea to check if anyone else is having problems reaching the site. That should help narrow things down a bit.&lt;/p&gt;&lt;div&gt;&lt;div messages=&quot;Can someone help me figure out why the Department of Telecommunications banned my site.,[object Object]&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;sigh,[object Object]&quot; date=&quot;06/28/2021&quot; username=&quot;Sky&quot; avatar=&quot;static/sky-avatar-a3e3e0b6bb4665a00a77336d6b444887.png&quot; rolecolor=&quot;teal.400&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;Working for me&quot; date=&quot;06/28/2021&quot; username=&quot;windows user&quot; avatar=&quot;static/windows-user-cc89d6254f4b87c3a84cf68de7d0594f.png&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;I&apos;m in kolkata, india,using jio as ISP&quot; date=&quot;06/28/2021&quot; username=&quot;Sky&quot; avatar=&quot;static/sky-avatar-a3e3e0b6bb4665a00a77336d6b444887.png&quot; rolecolor=&quot;teal.400&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;I&apos;m in noida&quot; date=&quot;06/28/2021&quot; username=&quot;windows user&quot; avatar=&quot;static/windows-user-cc89d6254f4b87c3a84cf68de7d0594f.png&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;Are you using your ISP&apos;s DNS though?&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;Oh right, it works with cloudflare DNS&quot; date=&quot;06/28/2021&quot; username=&quot;Sky&quot; avatar=&quot;static/sky-avatar-a3e3e0b6bb4665a00a77336d6b444887.png&quot; rolecolor=&quot;teal.400&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;Works for me,(im in india)&quot; date=&quot;06/28/2021&quot; username=&quot;Drac&quot; rolecolor=&quot;orange.500&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;probably because you aren&apos;t using your isp&apos;s dns&quot; date=&quot;06/28/2021&quot; username=&quot;Sky&quot; avatar=&quot;static/sky-avatar-a3e3e0b6bb4665a00a77336d6b444887.png&quot; rolecolor=&quot;teal.400&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;it&apos;s either that or some ISPs don&apos;t enforce the ban&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;It&apos;s working even on my phone&quot; date=&quot;06/28/2021&quot; username=&quot;windows user&quot; avatar=&quot;static/windows-user-cc89d6254f4b87c3a84cf68de7d0594f.png&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Oh so it’s a DNS issue then. Looks like it’s banned at the DNS level for Indian citizens. But windows user (if he doesn’t unknowingly have a custom DNS setup) is able to reach the site through his ISP’s DNS. Maybe different Indian ISPs enforce censorship at different levels?&lt;/p&gt;&lt;p&gt;I know this is something Turkish ISPs do extremely inconsistently as well. Plenty of VPN sites like NordVPN are banned by ISPs that have close ties to the state but others don’t seem to be bothered to enforce certain bans. At least I haven’t had any problems connecting to VPNs with the god-awful network provider I’m currently using, and yet my parents have. I could totally see this being the case for India as well.&lt;/p&gt;&lt;div&gt;&lt;div messages=&quot;what isp are you all using&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;Jio&quot; date=&quot;06/28/2021&quot; username=&quot;windows user&quot; avatar=&quot;static/windows-user-cc89d6254f4b87c3a84cf68de7d0594f.png&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;I&apos;m on airtel&quot; date=&quot;06/28/2021&quot; username=&quot;Drac&quot; rolecolor=&quot;orange.500&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;jio here too&quot; date=&quot;06/28/2021&quot; username=&quot;Sky&quot; avatar=&quot;static/sky-avatar-a3e3e0b6bb4665a00a77336d6b444887.png&quot; rolecolor=&quot;teal.400&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Great, so we have two people using Jio, one of whom can view the site and another person who can’t. Could the ban be enforced geographically? That’s not unheard of but it feels like the explanations we’re reaching for here are starting to get more far-fetched every time.&lt;/p&gt;&lt;div my=&quot;6&quot;&gt;&lt;/div&gt;&lt;p&gt;At this point, I take a break from the intense &lt;/p&gt;&lt;div&gt;investigative journalism&lt;/div&gt; to go back to doing what I was supposed to be doing for half an hour or so.&lt;p&gt;&lt;/p&gt;&lt;p&gt;I come back and have the idea of looking at the traceroute for the URL to see what IP the docs URL is being resolved to when I’m on an Indian VPN. But to my surprise I see…&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:974px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/135cb4073d3ae07cece8e3ca0a852e58/09e48/docs-successful.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:25.6%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAzElEQVQY04WPTU+DQBBAOWul0IJluxTY8rUUCkWNSkyMiRf//x96Zhdj4gF7eJnMTObNjJMXJc2ppe3OPL9MTNMbw2WcGUb64fKH394CzsfnF7odkVmFzErSosEL99yuQ4IoIVY1sdLIrGaflrYWiGWcQg8c654kP3FQNZtdjLuJWHn33Pm7nxjhhxIvkLb3H467FYRC4YezyFxmRDduwLHqeHx9p9C9zY38Go55SZ8f7CtmyMjWW2HFMq3Q3RNp3nJQDSIpWXnzwiW+AeAghfcYD40dAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/135cb4073d3ae07cece8e3ca0a852e58/490da/docs-successful.webp 250w,/static/135cb4073d3ae07cece8e3ca0a852e58/e333e/docs-successful.webp 500w,/static/135cb4073d3ae07cece8e3ca0a852e58/32f08/docs-successful.webp 974w&quot; sizes=&quot;(max-width: 974px) 100vw, 974px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/135cb4073d3ae07cece8e3ca0a852e58/63868/docs-successful.png 250w,/static/135cb4073d3ae07cece8e3ca0a852e58/0b533/docs-successful.png 500w,/static/135cb4073d3ae07cece8e3ca0a852e58/09e48/docs-successful.png 974w&quot; sizes=&quot;(max-width: 974px) 100vw, 974px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/135cb4073d3ae07cece8e3ca0a852e58/09e48/docs-successful.png&quot; alt=&quot;topgg docs load successfully&quot; title=&quot;topgg docs load successfully&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;div textalign=&quot;center&quot; font-weight=&quot;black&quot; mb=&quot;6&quot; color=&quot;text.100&quot; letter-spacing=&quot;12px&quot; font-size=&quot;2xl,,3xl,4xl,,6xl&quot;&gt;WHAT???&lt;/div&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/d25714d02acd877c1e2e1d4ef1e76062/eea4a/this-is-fine.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:56.400000000000006%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAv/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAaR6MVdFog//xAAaEAEBAAIDAAAAAAAAAAAAAAABAgMRABAh/9oACAEBAAEFAskBzZqQC/TFJ1//xAAWEQADAAAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8BiIj/xAAXEQADAQAAAAAAAAAAAAAAAAAAAQIS/9oACAECAQE/AZbybo//xAAaEAACAgMAAAAAAAAAAAAAAAAAASAhMXGB/9oACAEBAAY/AnRaWzCfIf/EABoQAAMBAAMAAAAAAAAAAAAAAAABESFBUWH/2gAIAQEAAT8hSQi5UQsLYiF7Alb1TQphIf/aAAwDAQACAAMAAAAQIP8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAFh/9oACAEDAQE/ELZi/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxQf/aAAgBAgEBPxASVyU7f//EABoQAQEAAgMAAAAAAAAAAAAAAAERACExQXH/2gAIAQEAAT8QThosI06uSWElA3XLk/IXa7gCNCXtzgvYZ1vAaAHmf//Z&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/d25714d02acd877c1e2e1d4ef1e76062/490da/this-is-fine.webp 250w,/static/d25714d02acd877c1e2e1d4ef1e76062/e333e/this-is-fine.webp 500w,/static/d25714d02acd877c1e2e1d4ef1e76062/54609/this-is-fine.webp 1000w,/static/d25714d02acd877c1e2e1d4ef1e76062/265b4/this-is-fine.webp 1280w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/d25714d02acd877c1e2e1d4ef1e76062/0479a/this-is-fine.jpg 250w,/static/d25714d02acd877c1e2e1d4ef1e76062/41099/this-is-fine.jpg 500w,/static/d25714d02acd877c1e2e1d4ef1e76062/a2510/this-is-fine.jpg 1000w,/static/d25714d02acd877c1e2e1d4ef1e76062/eea4a/this-is-fine.jpg 1280w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/d25714d02acd877c1e2e1d4ef1e76062/a2510/this-is-fine.jpg&quot; alt=&quot;this is fine&quot; title=&quot;this is fine&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Why is it working now? Maybe it’s just a VPN thing?&lt;/p&gt;&lt;div&gt;&lt;div messages=&quot;[object Object]&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div message=&quot;k let me reset my dns back to how it was then&quot; date=&quot;06/28/2021&quot; username=&quot;Sky&quot; avatar=&quot;static/sky-avatar-a3e3e0b6bb4665a00a77336d6b444887.png&quot; rolecolor=&quot;teal.400&quot;&gt;&lt;/div&gt;&lt;div message=&quot;ur the best&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;um, it works now?,how&quot; date=&quot;06/28/2021&quot; username=&quot;Sky&quot; avatar=&quot;static/sky-avatar-a3e3e0b6bb4665a00a77336d6b444887.png&quot; rolecolor=&quot;teal.400&quot;&gt;&lt;/div&gt;&lt;div messages=&quot;this is so weird,I hate this so much&quot; date=&quot;06/28/2021&quot; username=&quot;Xetera&quot; rolecolor=&quot;blue.300&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div textalign=&quot;center&quot; mb=&quot;6&quot;&gt;Why do these things always happen to me?&lt;/div&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:128px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/af6b692b9b8ab9c904798992421c636f/750d2/shuhuanlt.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:100%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFvElEQVQ4yyWSfVDT9wHGf7VjQ6qChgSs2KKoqFWc6CG2bljwZVdtr86bCO1wSL1zeth6stp2esVqLV0R1/pefMECVqkv+AZMD4uxIBJfIAqG95cQQkISYgh5z/ez2X3+f567z3OPpAEJm/kFQHLYbKliyGrQP67nekGhf8niJeJfu77g66/2sX1LFtUVN0lJXceCBX8Qy5a9458YEUmYIlwfOyc+KjJymhQRETlCchv6XnToeiSHXrfOa+yD4SF+LjnnT/pjEnPmzufJlau4njZRfaOCZw/qsLRpWJ+xAYViAuFhL3uDg4MJemnMnS1HbS/MTtwkSdZ+g9T5pHGMq6+3B5Oe1qpKb97WbaxelSwWxsWLylMFOJ404Gh+wpC2C1ezGvq7xe7PtovAkUFMi5rsyUxPJ1weljZerpAkt7ZTchgM+129WlwdrR7V2UJ2bM4Uy5csFx+mJrNx1SqUxUX49DqePbqHq7udYY0ajFqxcmmSyN682fef/HwCAn6jlJ7jfWaZK4aHcGh7hFPTKOrOnxVxsfPE2sTFNF08R9nxfL764AOGHj1EDBrx9Hbj0vbw3Kbq8gVRfuigqDx9wh84ciSzZ8z4kzTQ2LDCN2jGYzT43G3N4rN17wvZ6NGc/Oc/sN6voaXiGlf2fcPJrK1g1OGzmPDodfitZvz2QeHv7aLxZplPHipjevSsOqmj5u5GU6MaBgd87ZU3xKLXZjL71VeoPX0M490qum6V03ztErtSkinPzQGzEf+QDeF24jP3g80s+p8+JmryJL9cHobU29Cwv6e2BmtTvfd2/hERFR7Ou2/E01d5DVOdEkPtbSz3q1H/VEz22rU0Xr4EVhNeUz9efQ/eAb3APijeXbmCwMCRfsnS1lJiaFRjfKjy/vD5DhEhl7MiPo7SnGzUPxXSVlHK3YJjKE8eZe+mjeRs2IC7Q4O9sxlnbzduox48DpGTvZPAwCAhDWu7DOaWJgbqH4idGeli3KhRpC99k7I927my51OaSs9xde8OyvfupPfyOb5c/Q4VRw5g72jB1a/DPdAP+Lh1/SqBAQFIvkETto5WoS69wOo34kVo8Bj+HBfLic3pVOcfwNrUQJ/yJqeyMslOXkVGwuvsSnuf7ns12LpacZhNuF0uXE4n+3JzkfwOuxD9OurPFIjEmJliQqiMpDmzyP/kI3qrKnC0t+J8qqanpoobxw9juHOTHz/+iONZWzG0aHAMO7Ban2Gz2XmOhMUk6s4W8belb4pJ48OZFBrK99u2QNMDOm5cwdndyZBahbnmZ2hvxvuolvsHc8hdl4pR34/H7cE6aMXldGG32ZAOf7KdmMlRBAUFMSUigtkRE/ghawumW2Vorp7H1arBrlahuXiGrmsX0F0/j+q7PVSXFGOxDjFotuB0ujHqtFj0OqRvcw8hk7/MBIWCqRMnEDZuLJkrlvG0pIBH54vZn/l3Dn24CU3ZJYy1VahOH0F58Gt+KS9DeesO9+6qaHrciOqOEp/Hg6TV6pgSNY1XwhUoZDLGBIewcPo08jZlcP1AHmd370J5+ADtVy/+ep/7Z77n4cUidF1dtLV2Yh6w0PTgPoNGw/831HZ1sTQxifGysYTKQomImEhoSAg70pL54r01HE5YTGVyCqWpKSgP5aEqPIqypBir1Y59yEFbSxvtGs2vZW63B+nciXzeSkokXCYjeuo05sbEEPDb3xH96kSufZtD0fZtHFyfzr3CfLS3y1EVHePkl9ncqfqFJw2N1NepOHXoO+ruPWTY7kZauSSJ6ZGRTJ8USUJ8PHGxc1HI5UgjXuT30VNRFp7AUFOFsbqSlrILFHz+MWlJi0h9azl/TV5DxnupzIt5jXmx88j75t9Iry9YwMwpUcRER7No/nxmREcTEhLC6FGjkEaMYNakSLJS/sLujev5dF0yaxIWkrYkgbfnzyFi3FiCx4xGESrjpaAgRv0v818bxjq6h4aa5gAAAABJRU5ErkJggg==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/af6b692b9b8ab9c904798992421c636f/59bed/shuhuanlt.webp 128w&quot; sizes=&quot;(max-width: 128px) 100vw, 128px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/af6b692b9b8ab9c904798992421c636f/750d2/shuhuanlt.png 128w&quot; sizes=&quot;(max-width: 128px) 100vw, 128px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/af6b692b9b8ab9c904798992421c636f/750d2/shuhuanlt.png&quot; alt=&quot;shuhua from g-idle probably contemplating whether or not it&apos;s worth it for her to put up with the random inexplicable bullshit she has to deal with on a daily basis because of her job&quot; title=&quot;shuhua from g-idle probably contemplating whether or not it&apos;s worth it for her to put up with the random inexplicable bullshit she has to deal with on a daily basis because of her job&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;div textalign=&quot;center&quot; mb=&quot;6&quot; font-size=&quot;sm&quot; color=&quot;text.400&quot;&gt;I hate web development&lt;/div&gt;&lt;p&gt;To be fair, it’s possible (and most likely the real reason in this specific case) that it works now because the DNS query got cached at the router and/or browser level when Sky switched his DNS server to &lt;/p&gt;&lt;div href=&quot;https://1.1.1.1&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;1.1.1.1&lt;/div&gt; and got a successful response. But I’ve seen the same thing happen to at least 3 people where they inexplicably regain access to the site after a while, even when they haven’t switched their DNS server.&lt;p&gt;&lt;/p&gt;&lt;h2 id=&quot;possible-explanation&quot;&gt;&lt;a href=&quot;https://xetera.dev/#possible-explanation&quot;&gt;Possible explanation&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What I &lt;em&gt;think&lt;/em&gt; is going on here is that some Indian ISPs (most likely Jio in this case) are using some sort of heuristic to determine whether or not a DNS query to a site should be blocked, and then they are &lt;strong&gt;caching&lt;/strong&gt; the result in their own DNS servers to speed up subsequent lookups.&lt;/p&gt;&lt;p&gt;This is completely normal practice for DNS servers, but unfortunately it feels like they might be committing the cardinal sin of caching. Where they leave out part of the context that changes the response per-user, and are instead using a single shared cache key for every user when doing any lookup. On the user side of things, this is equivalent to opening up Instagram and seeing the feed of a different person every 30 minutes.&lt;/p&gt;&lt;p&gt;Chances are, the DNS query was cached when the original person who tried to reach the docs page got an error. Any subsequent requests going to the same DNS server ended up returning the same cached error response for as long as the TTL lasted. Then when the cache got reset, it got replaced with the correct IP originating from the request of a non-blocked user. Which allowed the original blocked user to also be able to access the site.&lt;/p&gt;&lt;p&gt;As for the reason for the censor itself, I’m still not sure but my team and I are speculating that it’s caused by an &lt;a href=&quot;https://en.wikipedia.org/wiki/Censorship_of_GitHub#India&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;old censorship of GitHub&lt;/a&gt;. Our docs page was being hosted on GitHub Pages and the ban is mostly likely the result of a lingering censorship of the GitHub Pages IPs. We’ve since moved to &lt;a href=&quot;https://netlify.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;Netlify&lt;/a&gt; and it seems that solved the issue. Or at the very least I haven’t seen anyone bring this up since then.&lt;/p&gt;&lt;h2 id=&quot;solution&quot;&gt;&lt;a href=&quot;https://xetera.dev/#solution&quot;&gt;Solution&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If you’re being affected by this, the easiest solution is to change your DNS server your device or preferably your router uses to &lt;/p&gt;&lt;div href=&quot;https://1.1.1.1&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;1.1.1.1&lt;/div&gt; or any other public DNS server that isn’t limited by Indian censorship. You do &lt;strong&gt;not&lt;/strong&gt; need a VPN as it doesn’t seem like the DoT uses packet inspection and relies only on DNS lookups. If you’re using GitHub Pages to host your site, switch over to an alternative like &lt;a href=&quot;https://pages.cloudflare.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;Cloudflare Pages&lt;/a&gt; or &lt;a href=&quot;https://netlify.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;Netlify&lt;/a&gt; to make sure you don’t run into the &lt;del&gt;great&lt;/del&gt; mediocre firewall of India.&lt;p&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[📚 Truthiness is not loose equality]]></title><link>https://xetera.dev/truthiness-equality/</link><guid isPermaLink="false">https://xetera.dev/truthiness-equality/</guid><pubDate>Sun, 13 Jun 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/truthiness-equality/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;There are a lot of beginners out there and even experienced developers who are confused about what it means for something to be truthy in Javascript. There’s also an assumption that many people never go out of their way to validate, where they think loose equality (&lt;/p&gt;&lt;div&gt;==&lt;/div&gt;) is the same thing as truthiness.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Truthiness makes some level of intuitive sense to most people who deal with it. If you show someone the following code snippet, chances are they will have a vague understanding of what’s going on. Even if they aren’t Javascript developers.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;if (&quot;test&quot;) {
  console.log(&quot;This will run&quot;)
}

if (&quot;&quot;) {
  console.log(&quot;This won&apos;t run!&quot;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But the explanation that is given is often muddled with misconceptions about how comparisons and equality works in Javascript.&lt;/p&gt;&lt;div&gt;&lt;div username=&quot;Xetera&quot; rolecolor=&quot;pink.300&quot; avatar=&quot;[object Object]&quot; message=&quot;So why do you think the if statement works if the string isn&apos;t empty?&quot; date=&quot;Today at 9:42 PM&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Tzuyu&quot; rolecolor=&quot;blue.400&quot; avatar=&quot;[object Object]&quot; message=&quot;Because a non-empty string is truthy, right?&quot; date=&quot;Today at 9:42 PM&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Xetera&quot; rolecolor=&quot;pink.300&quot; avatar=&quot;[object Object]&quot; message=&quot;Yeah, do you know what that means?&quot; date=&quot;Today at 9:43 PM&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Tzuyu&quot; rolecolor=&quot;blue.400&quot; avatar=&quot;[object Object]&quot; messages=&quot;Yeah,I think so,[object Object]&quot; date=&quot;Today at 9:44 PM&quot; reactions=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Xetera&quot; rolecolor=&quot;pink.300&quot; avatar=&quot;[object Object]&quot; message=&quot;Have you actually tried that?&quot; date=&quot;Today at 9:45 PM&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Tzuyu&quot; rolecolor=&quot;blue.400&quot; avatar=&quot;[object Object]&quot; messages=&quot;no&quot; date=&quot;Today at 9:45 PM&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Tzuyu&quot; rolecolor=&quot;blue.400&quot; avatar=&quot;[object Object]&quot; messages=&quot;wait wtf&quot; date=&quot;Today at 9:47 PM&quot; reactions=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div avatar=&quot;[object Object]&quot; username=&quot;Dubu&quot; message=&quot;lmao&quot; date=&quot;Today at 9:48 PM&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id=&quot;truthiness&quot;&gt;&lt;a href=&quot;https://xetera.dev/#truthiness&quot;&gt;Truthiness&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;It might be a good idea to take a step back and establish what it means for something to be truthy first. Many people get a feeling for how this works but don’t actually dive into the details. In simple terms, truthiness is just what you get when you throw the variable in question into the &lt;/p&gt;&lt;div&gt;Boolean()&lt;/div&gt; function.&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Boolean(&quot;&quot;) // false
Boolean(&quot;memes&quot;) // true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;so any time you’re calling an if statement, what that if statement is &lt;em&gt;actually&lt;/em&gt; doing is this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;if (Boolean(x)) {
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;/p&gt;&lt;div text=&quot;Ecma-262 spec&quot; color=&quot;pink.400&quot;&gt;The standard that defines how Javascript is supposed to behave.&lt;/div&gt; defines a function that it refers to as &lt;code&gt;ToBoolean&lt;/code&gt;, and all implicit boolean conversions including the explicit &lt;code&gt;Boolean()&lt;/code&gt; behave according to it with the &lt;a href=&quot;https://tc39.es/ecma262/multipage/abstract-operations.html#sec-toboolean&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;following lookup table&lt;/a&gt;.&lt;p&gt;&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Argument Type&lt;/th&gt;&lt;th&gt;Result&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Undefined&lt;/td&gt;&lt;td&gt;Return false.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Null&lt;/td&gt;&lt;td&gt;Return false.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Boolean&lt;/td&gt;&lt;td&gt;Return argument.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Number&lt;/td&gt;&lt;td&gt;If argument is +0𝔽, -0𝔽, or NaN, return false; otherwise return true.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;If argument is the empty String (its length is 0), return false; otherwise return true.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Symbol&lt;/td&gt;&lt;td&gt;Return true.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BigInt&lt;/td&gt;&lt;td&gt;If argument is 0ℤ, return false; otherwise return true.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Object&lt;/td&gt;&lt;td&gt;Return true.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;This might come as a surprise to some. What is truthy and what is falsy is clearly defined for each data type and has nothing to do with equality. This is the reason why you might expect arrays inside if statements to behave the way they do.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;if ([]) {
  console.log(&quot;This is always true&quot;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An array is an object which is always true regardless of its contents. If you’re a python developer, this is likely confusing since python’s lists implement &lt;/p&gt;&lt;div&gt;&lt;strong&gt;bool&lt;/strong&gt;&lt;/div&gt; differently and empty lists are considered falsy just like empty strings.&lt;p&gt;&lt;/p&gt;&lt;p&gt;So if truthiness isn’t based on &lt;code&gt;==&lt;/code&gt;, what’s going on with loose equality?&lt;/p&gt;&lt;h2 id=&quot;loose-equality&quot;&gt;&lt;a href=&quot;https://xetera.dev/#loose-equality&quot;&gt;Loose Equality&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Javascript has this quality where it tries to make guesses for you about what you’re trying to do and change the data it receives in order to have things make sense. This is called &lt;code&gt;coercion&lt;/code&gt; and it isn’t necessarily always bad. The examples above are a fairly common way for Javascript devs to do if statements. Checking things like&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;if (array.length) {
  console.log(&quot;This array has a length of at least 1&quot;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;to make sure an array isn’t empty. The same coercion happens when using the loose comparison operator &lt;code&gt;==&lt;/code&gt;, so why is plopping things inside &lt;code&gt;if&lt;/code&gt; statements acceptable but using &lt;code&gt;==&lt;/code&gt; isn’t?&lt;/p&gt;&lt;p&gt;For one, &lt;code&gt;ToBoolean&lt;/code&gt; is a unary function, meaning it has a single input and so it’s a lot easier to wrap one’s head around than &lt;code&gt;==&lt;/code&gt; which is a binary operator with 2 inputs. But another reason is because loose comparison is actually a recursive operator…&lt;/p&gt;&lt;p&gt;That’s right, loose comparison is implemented recursively. Meaning that comparison between two non-matching data types could recurse as much as 4 times, converting the inputs in each iteration into a different one and re-running the equality check.&lt;/p&gt;&lt;p&gt;There’s &lt;a href=&quot;https://felix-kling.de/js-loose-comparison/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;an extremely useful website&lt;/a&gt; on this topic that visually shows exactly how this process works between different kinds of inputs.&lt;/p&gt;&lt;p&gt;But basically in summary, equality is defined separately from truthiness. The only similarity they share is that truthiness is a form of coercion and loose equality can make use of a similar type of coercion although equality itself does not rely on the concept of truthiness.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🖼️ Optimizing images with WebP in Node.js]]></title><link>https://xetera.dev/converting-webp/</link><guid isPermaLink="false">https://xetera.dev/converting-webp/</guid><pubDate>Sun, 04 Apr 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/converting-webp/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;If you’re going to be accepting and serving images in your webserver, it’s a good idea to make sure they don’t take up HUGE amounts of space. Storage doesn’t grow on trees you know. A portion of what makes images take up a lot of space is its quality, images that look better take more space than those that look 💩.&lt;/p&gt;&lt;p&gt;File formats are another portion of that puzzle. Not all formats were created the same, something like GIF is an incredibly wasteful format as it stores each individual frame separately whereas something like MP4 stores the transitions between frames which makes it vastly more efficient for representing animation.&lt;/p&gt;&lt;p&gt;WebP is one of those file formats that allow for lossy compression in a way that (on average) makes high resolution images look better than what JPEG provides.&lt;/p&gt;&lt;div gridtemplatecolumns=&quot;1fr,,1fr 1fr&quot; mb=&quot;4&quot; gap=&quot;4&quot;&gt;&lt;div as=&quot;article&quot;&gt;&lt;div borderradius=&quot;md&quot; overflow=&quot;hidden&quot; maxwidth=&quot;100%&quot; mb=&quot;4&quot;&gt;&lt;div src=&quot;static/handong-cd8a0302f79cdcc3ab58a865ab43418d.png&quot; background=&quot;bgSecondary&quot; height=&quot;400px,,470px&quot; fallback=&quot;[object Object]&quot; width=&quot;100%&quot; objectfit=&quot;cover&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div justifycontent=&quot;space-between&quot; alignitems=&quot;center&quot; mb=&quot;3&quot; color=&quot;text.300&quot;&gt;&lt;div as=&quot;h3&quot; font-size=&quot;lg&quot; mb=&quot;0&quot;&gt;😔 Virgin PNG&lt;/div&gt;&lt;div mb=&quot;0&quot; font-size=&quot;sm&quot; font-weight=&quot;bold&quot; px=&quot;2&quot; borderradius=&quot;md&quot; colorscheme=&quot;linkedin&quot;&gt;7.1MB&lt;/div&gt;&lt;/div&gt;&lt;div mb=&quot;0&quot; font-size=&quot;[object Object]&quot; lineheight=&quot;180%&quot;&gt;That&apos;s crazy. Nobody wants to download this file and you don&apos;t want to serve
it either.&lt;/div&gt;&lt;/div&gt;&lt;div as=&quot;article&quot;&gt;&lt;div borderradius=&quot;md&quot; overflow=&quot;hidden&quot; maxwidth=&quot;100%&quot; mb=&quot;4&quot;&gt;&lt;div src=&quot;static/handong-554fe249520b8341f71cbf47dc6249ea.webp&quot; background=&quot;bgSecondary&quot; height=&quot;400px,,470px&quot; fallback=&quot;[object Object]&quot; width=&quot;100%&quot; objectfit=&quot;cover&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div justifycontent=&quot;space-between&quot; alignitems=&quot;center&quot; mb=&quot;3&quot; color=&quot;text.300&quot;&gt;&lt;div as=&quot;h3&quot; font-size=&quot;lg&quot; mb=&quot;0&quot;&gt;😎 Chad WebP&lt;/div&gt;&lt;div mb=&quot;0&quot; font-size=&quot;sm&quot; font-weight=&quot;bold&quot; px=&quot;2&quot; borderradius=&quot;md&quot; colorscheme=&quot;linkedin&quot;&gt;433KB&lt;/div&gt;&lt;/div&gt;&lt;div mb=&quot;0&quot; font-size=&quot;[object Object]&quot; lineheight=&quot;180%&quot;&gt;Now this is the good stuff. Look at how much smaller that is. Imagine not using webp in 2023.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;p&gt;Can you see the difference? I sure can’t. Try opening them in a new tab and zoom in, it’s still not noticeable. The conversion from Png WebP here is saving us that many bytes which makes the image load faster. That’s a &lt;/p&gt;&lt;div text=&quot;6x+ reduction in file size&quot; class=&quot;text-indigo-300&quot;&gt;The example image is optimized to load faster on your browser. These values are from the raw images that were used.&lt;/div&gt; for free.&lt;p&gt;&lt;/p&gt;&lt;p&gt;There are some implications of using improved file formats of course. A browser first has to be able to support the file format that you’re using so outdated browsers like Internet Explorer and Safari don’t support it fully.&lt;/p&gt;&lt;h2 id=&quot;getting-started&quot;&gt;&lt;a href=&quot;https://xetera.dev/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Let’s get started with converting images in Javascript by installing the basic dependencies. Make sure you use the &lt;code&gt;npm&lt;/code&gt; version of these commands if you’re not on yarn.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ yarn add fluent-ffmpeg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We’re going to be using ffmpeg to do our image conversions. If you’re not familiar with ffmpeg, it’s the god tool for working with any kind of media. Images, sound, videos, gifs, subtitles. It’ll take anything and modify it in any way you want. Here’s a simple example that works on the commandline.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ ffmpeg -i image.png image.jpeg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nothing too fancy here, we’re simply setting &lt;code&gt;image.png&lt;/code&gt; as the input file and turning it into a &lt;code&gt;image.jpeg&lt;/code&gt;. Ffmpeg is able to infer that we want a &lt;/p&gt;&lt;div text=&quot;Jpeg&quot; class=&quot;text-green-300&quot;&gt;JPEG and JPG refer to the exact same file type, just with different names.&lt;/div&gt; output We can also pass in any kind of option we want. If we’re converting to WebP, we can control the quality of the resulting file through these options.&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ ffmpeg -i image.png -quality 50 image.webp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will produce a fairly low quality but an amazingly small webp version of our image. The default ffmpeg value for webp images is 75 which I find to be adequate but you can feel free to play around with it as you like.&lt;/p&gt;&lt;p&gt;CLI programs can be a bit of a pain to run so let’s jump on fluent-ffmpeg which is a more convenient version of the api.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{title: &amp;quot;lib/image.ts&amp;quot;, lines:true}&quot;&gt;import ffmpeg from &quot;fluent-ffmpeg&quot;
import * as fs from &quot;fs&quot;
import { Readable } from &quot;stream&quot;

function convertImage(imagePath: string, outputName: string) {
  ffmpeg().input(image).saveToFile(outputName)
}

convertImage(&quot;./image.png&quot;, &quot;./image.webp&quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This produces the same output as the one above, but it’s not very practical, let’s look at an express example where a user uploads an image using &lt;code&gt;multipart/form-data&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines: true}&quot;&gt;import express from &quot;express&quot;
import multer from &quot;multer&quot;
import fs from &quot;fs/promises&quot;
import { convertImage } from &quot;./lib/image&quot;

const upload = multer({ dest: &quot;uploads/&quot; })

const app = express()

app.post(&quot;/profile&quot;, upload.single(&quot;avatar&quot;), async (req, res, next) =&amp;gt; {
  convertImage(req.file.path, &quot;./image.webp&quot;)
  // image.webp is now available on disk
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That’s it, that’s all you need to convert images to webp, wasn’t so problematic was it? Except there’s a problem, this method of doing conversions is extremely inefficient. We’re writing the original file to disk first even though we just end up reading it again right afterwards. Thankfully multer allows only saving things in memory without writing to disk with the following.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lang:false}&quot;&gt;const upload = multer({ storage: multer.memoryStorage() })
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p class=&quot;text-sm leading-7&quot;&gt;There are basically no other multipart parsers that do this. I spent many hours looking and multer was the only one. Kinda crazy...&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Images, which are just binary data in memory, are represented with the &lt;code&gt;Buffer&lt;/code&gt; data type and ffmpeg by default takes a file path. Being a CLI program, we can pipe a stream of bytes into it in the CLI like this.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ cat image.png | ffmpeg -i pipe:0 image.webp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In english terms that’s equivalent to&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Take the contents of image.png, &lt;em&gt;pipe&lt;/em&gt; it across this program which takes its input from &lt;code&gt;pipe:0&lt;/code&gt; and convert it to image.webp.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;code&gt;pipe:0&lt;/code&gt; here being stdout that we pushed the contents of image.png into. If you’re not familiar with unix pipes definitely check look into them.&lt;/p&gt;&lt;p&gt;In fluent-ffmpeg, doing this kind of piping requires the input to be a &lt;code&gt;ReadableStream&lt;/code&gt;. The conversion between Buffers and Streams is a bit hacky and it involves manually disabling some internal methods but it’s doable and works just fine.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{title: &amp;quot;lib/image.ts&amp;quot;, lines:true}&quot;&gt;import { Readable } from &quot;stream&quot;

function convertImage(image: Readable, outputName: string) {
  ffmpeg().input(image).saveToFile(outputName)
}

export function bufferToStream(buffer: Buffer): Readable {
  const readable = new Readable()
  readable._read = () =&amp;gt; {}
  readable.push(buffer)
  readable.push(null)
  return readable
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;this now lets us patch the previous function like so.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines: true}&quot;&gt;import express from &quot;express&quot;
import multer from &quot;multer&quot;
import { bufferToStream, convertImage } from &quot;./lib/image&quot;

const upload = multer({ storage: multer.memoryStorage() })

const app = express()

app.post(&quot;/profile&quot;, upload.single(&quot;avatar&quot;), async (req, res, next) =&amp;gt; {
  const stream = bufferToStream(req.file.buffer)
  convertImage(stream, &quot;./image.webp&quot;)
  // image.webp is now available on disk
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This method works pretty well but we still have the same issue on the &lt;em&gt;other end&lt;/em&gt;. We’re saving an image to disk but often we want to do something like upload it to S3 or save it somewhere else and writing the image to a file ends up being a pointless operation that takes time and resources. For this example we’re going to pretend we want an output we can pass along to the AWS sdk to upload on S3 instead of saving on disk. &lt;a href=&quot;https://wasabi.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;https://wasabi.com&lt;/a&gt; is a great service for this.&lt;/p&gt;&lt;p&gt;Thankfully, ffmpeg allows outputting a stream just as it allows for a stream input. To do that we will use a &lt;code&gt;PassThrough&lt;/code&gt; stream which, as the name states, just passes the stream through. We use this to capture the output of the conversion.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{title: &amp;quot;lib/image.ts&amp;quot;, lines:true}&quot;&gt;import { Readable, PassThrough } from &quot;stream&quot;

function convertImage(image: Readable, outputFormat: string) {
  const passthrough = new PassThrough()
  ffmpeg()
    .input(image)
    .outputFormat(outputFormat)
    .stream(passthrough, { end: true })
  return passthrough
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that we’re passing a stream to ffmpeg it can no longer infer what filetype it needs to turn the image into so we need to explicitly tell it that we’re looking to convert to a specific format.&lt;/p&gt;&lt;p&gt;For testing purposes, we can try writing this to a file manually.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;app.post(&quot;/profile&quot;, upload.single(&quot;avatar&quot;), (req, res, next) =&amp;gt; {
  const stream = bufferToStream(req.file.buffer)
  const output = convertImage(stream, &quot;webp&quot;)
  output.pipe(fs.createWriteStream(&quot;./image.webp&quot;))
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Aaand it work- wait… what the hell is this?&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:170px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/169b5ebcb27ebe417c194b0e9b67151d/04472/wtf.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:108.8235294117647%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAWCAYAAADAQbwGAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAY0lEQVQ4y2Pg4+P7T03MMGrgqIF8/3l5efHyiTYQWSMPDw8Yw8TwGcpAjOsEBAT+CwoKUuZCGObm5v6/Zs2a/5cvX/6vrKz8n4OD4z8/P/8gMZCqXqZJpFA12Yzm5VEDcRsIADbgBxOs7fl/AAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/169b5ebcb27ebe417c194b0e9b67151d/9b889/wtf.webp 170w&quot; sizes=&quot;(max-width: 170px) 100vw, 170px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/169b5ebcb27ebe417c194b0e9b67151d/04472/wtf.png 170w&quot; sizes=&quot;(max-width: 170px) 100vw, 170px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/169b5ebcb27ebe417c194b0e9b67151d/04472/wtf.png&quot; alt=&quot;wtf&quot; title=&quot;wtf&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;The file is corrupted?? What on Earth could be going on?&lt;/p&gt;&lt;h2 id=&quot;debugging-stream-issues&quot;&gt;&lt;a href=&quot;https://xetera.dev/#debugging-stream-issues&quot;&gt;Debugging stream issues&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The exact same command we tried worked with a file, why is it not working with a stream as opposed to a file target? To start debugging this, we first need to understand how the webp spec works and how ffmpeg interacts with streams.&lt;/p&gt;&lt;p&gt;The webp spec says that images need to have the block size of the file at the beginning of the file like so.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:942px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/485917b75784974c3f5c49ad4b5dff8c/f1901/spec.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:60.8%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAA7DAAAOwwHHb6hkAAABUElEQVQoz51TAXKDIBDk//9sVDhQFBSiZjt7Jm2SJp1Ondlhwbtl7zzN+XxG11mIEzjnICL477NtG0zKM1LOSPN8IM9YSr1DeeRLwVyuWAqWWjHEEeIDppRhQj/AWwcvAu8E3tLtsRfrILe9E0hnEUKPYZweEIYIT50hwnBjfUArAivh4E5grUfnPKz3x7l4dOI1MU7pB8aU0ccRhgFMbCjCJO/RWEHz4dA0TkVuYrxIwmtBQgXV7hDh+gHO9+qQkPDN788Z+1zyfemGTda+DFG/0rbtWNcN67pe12f+BtuGUioMRcZxRNu2uqYpYZ5nFf/X2JRadfY4g6fTCSGEl8GXywX7vr8F39OpIaGyuw5213UKOm6aBtZaHfwYR62AIJ+mSUEeY0QpRdtl+KcwiViWBbXWL7AnXBnzl0cd0h1vojvennPWHlLoueTfcBP8BNIBoIVvhpnTAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/485917b75784974c3f5c49ad4b5dff8c/490da/spec.webp 250w,/static/485917b75784974c3f5c49ad4b5dff8c/e333e/spec.webp 500w,/static/485917b75784974c3f5c49ad4b5dff8c/a0d96/spec.webp 942w&quot; sizes=&quot;(max-width: 942px) 100vw, 942px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/485917b75784974c3f5c49ad4b5dff8c/63868/spec.png 250w,/static/485917b75784974c3f5c49ad4b5dff8c/0b533/spec.png 500w,/static/485917b75784974c3f5c49ad4b5dff8c/f1901/spec.png 942w&quot; sizes=&quot;(max-width: 942px) 100vw, 942px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/485917b75784974c3f5c49ad4b5dff8c/f1901/spec.png&quot; alt=&quot;spec&quot; title=&quot;spec&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;A working webp image will have a file size signature where the image size is between the first 4th and 7th bytes.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:734px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/5372de134d6afddcc2b0b17445835aa2/c6d67/working.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:14.399999999999999%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAq0lEQVQI1x3Ha26DMBAAYS5QgWlUwNhe7/oBJJHaqvc/20Tpr/lmmOrIXByzTcwycts8i7/48h0RI2dBUqBoZt83/LbyOTvcNOOmEefennDjx3+H9qhIV7Ze2Uohlic//c63Cn9ZObTgy4PYnkS7CHqxSsPbin9/2EnlwPdf1j0yHK2jWklmaEhIapzVOG3h0oUSEj51vJ6kYEisBGlY3Um5kE3IaiS7E1PkBYggUO6lc6zSAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/5372de134d6afddcc2b0b17445835aa2/490da/working.webp 250w,/static/5372de134d6afddcc2b0b17445835aa2/e333e/working.webp 500w,/static/5372de134d6afddcc2b0b17445835aa2/28c4f/working.webp 734w&quot; sizes=&quot;(max-width: 734px) 100vw, 734px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/5372de134d6afddcc2b0b17445835aa2/63868/working.png 250w,/static/5372de134d6afddcc2b0b17445835aa2/0b533/working.png 500w,/static/5372de134d6afddcc2b0b17445835aa2/c6d67/working.png 734w&quot; sizes=&quot;(max-width: 734px) 100vw, 734px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/5372de134d6afddcc2b0b17445835aa2/c6d67/working.png&quot; alt=&quot;working&quot; title=&quot;working&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;However, when we pipe the data directly out of ffmpeg without writing to disk using this command (which is the equivalent of the original problematic js code).&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ cat image.png | ffmpeg -i pipe:0 -f webp pipe:1 &amp;gt; output.webp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The exact same file looks like this… why?&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:724px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/055cd4b0b1d2dde702e49fe0050fc4ef/a242d/converted.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:12.8%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAArUlEQVQI1x2KQW6DMBAA+UGDQ0gx2IvttRdoqHqIqv7/Y1MlpxmNprs+HMPec90u3NaBKZxM8sMUvmjV2DZDtfA4do5jf/urhWVBouBcT9/3b7rLB12SzG0p+KiMs3Kuhb8Uea4zv9FTfMD5zBAr92CM4fU1BoncZWTWkzUlYml82pOumRHUMBVSqKS601om1QlrHo2ZKMZi32Q5KKmSwo5UpehCUUNbIasievIPjnBSjZ5CyfEAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/055cd4b0b1d2dde702e49fe0050fc4ef/490da/converted.webp 250w,/static/055cd4b0b1d2dde702e49fe0050fc4ef/e333e/converted.webp 500w,/static/055cd4b0b1d2dde702e49fe0050fc4ef/007bf/converted.webp 724w&quot; sizes=&quot;(max-width: 724px) 100vw, 724px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/055cd4b0b1d2dde702e49fe0050fc4ef/63868/converted.png 250w,/static/055cd4b0b1d2dde702e49fe0050fc4ef/0b533/converted.png 500w,/static/055cd4b0b1d2dde702e49fe0050fc4ef/a242d/converted.png 724w&quot; sizes=&quot;(max-width: 724px) 100vw, 724px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/055cd4b0b1d2dde702e49fe0050fc4ef/a242d/converted.png&quot; alt=&quot;converted&quot; title=&quot;converted&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Essentially, ffmpeg doesn’t know the size of the image as it’s going over it so it uses 4 null bytes &lt;code&gt;00 00 00 00&lt;/code&gt; as a placeholder and plans to seek back to the beginning of the image when it’s done to replace it with the size of the image it just read. Except when piping to stdout, ffmpeg is unable to seek back. Try to see if you can spot where the missing &lt;code&gt;2e 8a 03 00&lt;/code&gt; bytes might have gone instead of the header.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:738px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/038335b7523e08c3e456aef1bb5e67b5/774b6/tail.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:21.999999999999996%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAYAAACOXx+WAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA0klEQVQY0y2PSW7DMBRDfYEilqUvyZqHxEmbrHr/u73CRhcEuSIfF6kGOTTbFFRfWYug3YHe3+g4yckRXaBXR6qVFAw5bmwirFpYjUepG9v2xapuLDlnaq3kWAh7I+yVGDMxFYy1WDFYc/qGWEFEX9mIkHInlYZzFmP0pcVOwX8s9sdjXwZ5eHz+4OsvYbx53BujDd4/k+f3i+fROR6F0hpt3tlTvUacM2itWE66MQYlNWLsxDhIZ06d0AclKoqcV/U/scLbG/oinOQ+KSlchWfxHz8YaGbzOzuvAAAAAElFTkSuQmCC&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/038335b7523e08c3e456aef1bb5e67b5/490da/tail.webp 250w,/static/038335b7523e08c3e456aef1bb5e67b5/e333e/tail.webp 500w,/static/038335b7523e08c3e456aef1bb5e67b5/5dd3d/tail.webp 738w&quot; sizes=&quot;(max-width: 738px) 100vw, 738px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/038335b7523e08c3e456aef1bb5e67b5/63868/tail.png 250w,/static/038335b7523e08c3e456aef1bb5e67b5/0b533/tail.png 500w,/static/038335b7523e08c3e456aef1bb5e67b5/774b6/tail.png 738w&quot; sizes=&quot;(max-width: 738px) 100vw, 738px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/038335b7523e08c3e456aef1bb5e67b5/774b6/tail.png&quot; alt=&quot;tail&quot; title=&quot;tail&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;I’m not sure why, but instead of warning you that piping a webp output to stdout will not work, ffmpeg decides to go ahead and just do it anyways and adds the file size at the end of the image. This will likely be fixed in the future by failing with a warning, but as of version 4.2.4, ffmpeg does weird things with webp outputs. (The same thing applies for other file formats that have block sizes in the header like FLAC files).&lt;/p&gt;&lt;p&gt;One interesting caveat to this is if the image is small enough for ffmpeg to read in one go without separating into multiple chunks (less than a handful KBs), it doesn’t have to seek back to the beginning and will properly include the file size in the header from the start.&lt;/p&gt;&lt;h2 id=&quot;putting-it-together&quot;&gt;&lt;a href=&quot;https://xetera.dev/#putting-it-together&quot;&gt;Putting it Together&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This bug isn’t the end of the world for us though. We can fix it by simply moving the last 4 bytes of the image into the 4-7 byte position. Javascript has very efficient methods on typed arrays and buffers that let us move data around without much overhead called &lt;code&gt;copyWithin&lt;/code&gt; and &lt;code&gt;slice&lt;/code&gt;. &lt;code&gt;copyWithin&lt;/code&gt; is similar to the performant memcpy and memmove in C (it even has the same gross type signature) and &lt;code&gt;slice&lt;/code&gt; returns a view without copying anything much like the &lt;code&gt;&amp;amp;str&lt;/code&gt; type in Rust. Definitely &lt;em&gt;not at all&lt;/em&gt; confusing with &lt;code&gt;Array.prototype.slice&lt;/code&gt; which is often used to explicitly copy arrays. Good job Javascript.&lt;/p&gt;&lt;p&gt;One problem we run into when implementing this fix is that streams are not directly editable and we have to consume the entire stream first and then concat the chunks into a single buffer before we can start picking apart the bytes.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{title: &amp;quot;lib/image.ts&amp;quot;, lines:true}&quot;&gt;import { Readable, PassThrough } from &quot;stream&quot;

function convertImage(image: Readable, outputFormat: string) {
  return new Promise((resolve, reject) =&amp;gt; {
    const chunks: Buffer[] = []
    const passthrough = new PassThrough()
    ffmpeg()
      .input(image)
      .outputFormat(outputFormat)
      .on(&quot;error&quot;, reject)
      .stream(passthrough, { end: true })
    passthrough.on(&quot;data&quot;, data =&amp;gt; chunks.push(data))
    passthrough.on(&quot;error&quot;, reject)
    passthrough.on(&quot;end&quot;, () =&amp;gt; {
      const originalImage = Buffer.concat(chunks)
      const editedImage = originalImage
        // copy everything after the last 4 bytes into the 4th position
        .copyWithin(4, -4)
        // trim off the extra last 4 bytes ffmpeg added
        .slice(0, -4)
      return resolve(editedImage)
    })
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And it worked!&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/b09cdf4d0a2877be2c2686c71a55fa9d/0047d/jiu_umbrella.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.8%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAwb/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABUztSaFjpRP/EABsQAAEEAwAAAAAAAAAAAAAAAAIAAwQREBIU/9oACAEBAAEFAhGxKsSY46sUT/I0v//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPwGNj//EABwQAAICAgMAAAAAAAAAAAAAAAABAiEQEjFRkf/aAAgBAQAGPwIWvV4c40yNUcP0/8QAGhAAAgMBAQAAAAAAAAAAAAAAAREAITEQQf/aAAgBAQABPyF6M24J1mChLodlexG0oh8Z/9oADAMBAAIAAwAAABBAL//EABcRAAMBAAAAAAAAAAAAAAAAAAABETH/2gAIAQMBAT8QykZ//8QAFhEAAwAAAAAAAAAAAAAAAAAAARAx/9oACAECAQE/ECiv/8QAGhABAQEAAwEAAAAAAAAAAAAAAREAITFBcf/aAAgBAQABPxBVYVQn0Lp7hFVtfXUMz3LewrvjVOW7qkR50+0+rf/Z&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/b09cdf4d0a2877be2c2686c71a55fa9d/490da/jiu_umbrella.webp 250w,/static/b09cdf4d0a2877be2c2686c71a55fa9d/e333e/jiu_umbrella.webp 500w,/static/b09cdf4d0a2877be2c2686c71a55fa9d/54609/jiu_umbrella.webp 1000w,/static/b09cdf4d0a2877be2c2686c71a55fa9d/de0ca/jiu_umbrella.webp 1500w,/static/b09cdf4d0a2877be2c2686c71a55fa9d/32898/jiu_umbrella.webp 1620w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/b09cdf4d0a2877be2c2686c71a55fa9d/0479a/jiu_umbrella.jpg 250w,/static/b09cdf4d0a2877be2c2686c71a55fa9d/41099/jiu_umbrella.jpg 500w,/static/b09cdf4d0a2877be2c2686c71a55fa9d/a2510/jiu_umbrella.jpg 1000w,/static/b09cdf4d0a2877be2c2686c71a55fa9d/c58a3/jiu_umbrella.jpg 1500w,/static/b09cdf4d0a2877be2c2686c71a55fa9d/0047d/jiu_umbrella.jpg 1620w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/b09cdf4d0a2877be2c2686c71a55fa9d/a2510/jiu_umbrella.jpg&quot; alt=&quot;jiu umbrella&quot; title=&quot;jiu umbrella&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now we can publish to s3 easily with&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines: true, name: &amp;quot;lib/upload&amp;quot;}&quot;&gt;import express from &quot;express&quot;
import multer from &quot;multer&quot;
import { S3, Endpoint } from &quot;aws-sdk&quot;
import { credentials } from &quot;./config&quot;
import { bufferToStream, convertImage } from &quot;./lib/image&quot;

const upload = multer({ storage: multer.memoryStorage() })
const app = express()

export const wasabi = new S3({
  endpoint: new Endpoint(&quot;s3.wasabisys.com&quot;),
  credentials,
  s3ForcePathStyle: true,
})

app.post(&quot;/profile&quot;, upload.single(&quot;avatar&quot;), async (req, res, next) =&amp;gt; {
  const stream = bufferToStream(req.file.buffer)
  const output = await convertImage(stream, &quot;webp&quot;)
  await wasabi
    .putObject({
      Bucket: process.env.MY_BUCKET,
      ContentType: &quot;image/webp&quot;,
      Key: &quot;test.webp&quot;,
      Data: output,
    })
    .promise()
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And that’s all! You have an optimized webp optimized image uploader for your app. You might want to also convert to some fallback formats like jpeg if you want to support older browsers just in case.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[☄️ Integrating Typescript with Next.js]]></title><link>https://xetera.dev/typescript-nextjs/</link><guid isPermaLink="false">https://xetera.dev/typescript-nextjs/</guid><pubDate>Sat, 02 Jan 2021 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/typescript-nextjs/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;div background=&quot;bgSecondary&quot;&gt;&lt;div alignitems=&quot;center&quot;&gt;&lt;div mr=&quot;2&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;1em&quot; width=&quot;1em&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm-1-5h2v2h-2v-2zm2-1.645V14h-2v-1.5a1 1 0 0 1 1-1 1.5 1.5 0 1 0-1.471-1.794l-1.962-.393A3.501 3.501 0 1 1 13 13.355z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/div&gt;&lt;strong&gt;Info&lt;/strong&gt;&lt;/div&gt;&lt;div mb=&quot;0&quot;&gt;This post is specifically aimed at &lt;a href=&quot;https://github.com/prisma/prisma&quot; rel=&quot;external&quot;&gt;Prisma&lt;/a&gt; users but you should be able to use it with any ORM (or no ORM ot all if you roll that way).&lt;/div&gt;&lt;/div&gt;&lt;p&gt;One of the most annoying things about integrating different technologies together is losing static typing along the way. This is my biggest complaint when it comes to working with databases without an ORM, but is also a big issue with HTTP APIs. GraphQL and &lt;a href=&quot;https://github.com/dotansimha/graphql-code-generator&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;GraphQL Code Generator&lt;/a&gt; solve this problem beautifully, but GraphQL can still be very frustrating to work with from time to time due to its immature ecosystem. Sometimes you just want to be able to use HTTP and call it a day.&lt;/p&gt;&lt;p&gt;Next.JS is an amazing technology that allows us to use Typescript, but even with static typing and an ORM that has static definitions for things like a &lt;code&gt;User&lt;/code&gt; stored in the database, that &lt;code&gt;User&lt;/code&gt; is usually not the same &lt;code&gt;User&lt;/code&gt; you send to the frontend as API responses so often times you end up losing that static typing along the way.&lt;/p&gt;&lt;p&gt;Thankfully, to solve this problem, Next.js lets us share code between our frontend and the backend where we actually don’t have to lose the type information along the way.&lt;/p&gt;&lt;p&gt;Here’s an example of thow that’s possible:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{h: &amp;quot;4-8,16&amp;quot;, lines: true, title: &amp;quot;/pages/api/user/[userId].ts&amp;quot;}&quot;&gt;import { NextApiRequest, NextApiResponse } from &quot;next&quot;
import { db } from &quot;../your-database-file&quot;

const response = (id: string) =&amp;gt; {
  return db.user.findUnique({
    where: { id },
  })
}

export default async (req: NextApiRequest, res: NextApiResponse) =&amp;gt; {
  const { userId } = req.query

  res.json(await response(userId))
}

export type UserResponse = PromiseReturnType&amp;lt;typeof response&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we’re querying the database with Prisma which generates type information for exactly the shape of data you’re querying for the database which is why the return value isn’t explicit in the &lt;code&gt;response&lt;/code&gt; function. It’s already inferred with the exact return value. There is a small issue however, which is that the type is actually &lt;code&gt;Promise&amp;lt;Image&amp;gt;&lt;/code&gt; and not &lt;code&gt;Image&lt;/code&gt;, in order to get the &lt;code&gt;Image&lt;/code&gt; type out, we have to unwrap the Promise type. If you’re a Prisma user, then you can simply use a type-level function it exports called &lt;code&gt;PromiseReturnType&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { PromiseReturnType } from &quot;@prisma/client&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If not, you can use some manual Typescript magic instead.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lang:false}&quot;&gt;export type PromiseReturnType&amp;lt;T&amp;gt; = ReturnType&amp;lt;T&amp;gt; extends Promise&amp;lt;infer R&amp;gt;
  ? R
  : never
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;If you’ve never looked into the &lt;code&gt;infer&lt;/code&gt; keyword or conditional types, I highly recommend you do, they’re fantastic.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;This way we can declare the types of the responses we get from an endpoint &lt;em&gt;inside&lt;/em&gt; the endpoint file itself which makes importing much easier and also enables using type inference for database results from ORMs that are statically typed without repeating the typings.&lt;/p&gt;&lt;p&gt;All of this sounds pretty good so far, but when it comes to importing things, some of you might be wondering:&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;div borderradius=&quot;md&quot; message=&quot;Hold on, am I going to have to import an API endpoint file in my frontend now? This is going to create issues importing backend code for sure.&quot; username=&quot;You, reading this&quot; rolecolor=&quot;blue.300&quot; date=&quot;Today at 4:20 PM&quot; avatar=&quot;[object Object]&quot; reactions=&quot;[object Object],[object Object]&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;But not to worry, as of &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;Typescript 3.8&lt;/a&gt;,
we can import &lt;em&gt;just&lt;/em&gt; types from a typescript file, meaning it’s possible to do this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{title: &amp;quot;/pages/home.tsx&amp;quot;}&quot;&gt;import type { HomeResponse } from &quot;./api/home.ts&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Making sure that you don’t accidentally bring in an entire backend bundle to your frontend when trying to share types.&lt;/p&gt;&lt;p&gt;This is all nice and everything, but what if we could write a function that could do the work of wrapping a function that returns a promise and replying with the response value, maybe something like:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lang:false, lines:true}&quot;&gt;import { NextApiRequest, NextApiResponse } from &quot;next&quot;

type Handle&amp;lt;T&amp;gt; = (req: NextApiRequest, res: NextApiResponse) =&amp;gt; Promise&amp;lt;T&amp;gt;

function respond&amp;lt;T&amp;gt;(f: Handle&amp;lt;T&amp;gt;) {
  return async (req: NextApiRequest, res: NextApiResponse) =&amp;gt; {
    try {
      const result = await f(req, res)
      res.json(result)
    } catch (err) {
      res.statusCode = 500
      res.json({ message: err })
    }
  }
}

const handle: Handle = (req, res) =&amp;gt; {
  return db.users.findMany({})
}

export type UsersResponse = PromiseReturnType&amp;lt;typeof handle&amp;gt;

export default respond(handle)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Unfortunately, this doesn’t work because of &lt;a href=&quot;https://github.com/Microsoft/TypeScript/issues/17574&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;this issue about generic values&lt;/a&gt;. Otherwise we would be able to get the type inference working flawlessly. Typescript core team pls…&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[💬 Whatsapp doesn't deserve your business]]></title><link>https://xetera.dev/whatsapp-sucks/</link><guid isPermaLink="false">https://xetera.dev/whatsapp-sucks/</guid><pubDate>Wed, 09 Dec 2020 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/whatsapp-sucks/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2&gt;&lt;a href=&quot;https://www.wired.com/2015/09/whatsapp-serves-900-million-users-50-engineers/&quot; target=&quot;_blank&quot; rel=&quot;noopener external&quot;&gt;Why WhatsApp Only Needs 50 Engineers for Its 900M Users&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This was one of the headlines that WhatsApp was praised for in 2015, attributing it to their use of Erlang. The engineer inside me still feels giddy at the thought of this since I’m a big fan of functional programming fan myself, but something about this headline doesn’t sit right with me anymore. Every time I go to &lt;a href=&quot;https://web.whatsapp.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;https://web.whatsapp.com&lt;/a&gt; to check my messages from the last 3 people in my friend circle who still use this app, and I wait for the page to load for 10 minutes only to realize that my phone hasn’t been turned on for some time —and that I need to enter my password on my phone to use a chat app on desktop— I think of this headline and it makes me angrier every time.&lt;/p&gt;&lt;h1 id=&quot;laziness&quot;&gt;&lt;a href=&quot;https://xetera.dev/#laziness&quot;&gt;Laziness&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The last time I was using this app regularly was around 4 years ago. That was back in the olden times when there were no stickers and ehh… uhm… yeah that’s it actually. Everything else was exactly the same. WhatsApp, with their team of the last 50 Erlang developers on Earth, have been busy doing absolutely nothing, at least on the user-facing side. Meanwhile they’ve been growing to a mind-blowing scale of &lt;a href=&quot;https://techcrunch.com/2020/10/29/whatsapp-is-now-delivering-roughly-100-billion-messages-a-day/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;100 billion messages sent per day&lt;/a&gt;, which is more messages that gets sent through the global SMS infrastructure. This is even more impressive considering that they don’t allow consumer bots on their platform the way Slack or Discord does, but perhaps less so, when you realize that there is still widespread businesses automation.&lt;/p&gt;&lt;p&gt;The reason why this bothers me is because WhatsApp enjoys the leisure of a term I’m about to coin right now on the spot, called privacy-oriented laziness. Which is where your design decisions as a tech company based on privacy are a form of marketing for your users and a way of doing less work for your engineers. Building a system that tracks all of its users, while potentially very useful for growing a business, is a huge hassle engineering wise. Duckduckgo for example, doesn’t have to deal with the work that goes into building a personalized search engine because that’s just not what they do. WhatsApp doesn’t store any messages from users for the sake of being privacy focused but that also means they have a lot less to worry about. Of course, when you’re at the scale of WhatsApp, every technical problem is a massive challenge that requires completely rethinking the problem itself and not having to store messages doesn’t end up being as big of a win. But the domain of problems that you’re solving ends up being significantly smaller than if you had to worry about storing trillions of data points a month just for user messages alone.&lt;/p&gt;&lt;div&gt;&lt;div message=&quot;Hey man, why does a chat program need features? Isn&apos;t it enough for it to just allow you to chat with people?&quot; username=&quot;Definitely Not a Facebook Employee&quot; rolecolor=&quot;pink.700&quot; date=&quot;Today at 5:05 AM&quot; avatar=&quot;[object Object]&quot; reactions=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div message=&quot;If I can chat on it, it&apos;s good bro.&quot; username=&quot;Boomer&quot; rolecolor=&quot;orange.700&quot; date=&quot;Today at 5:10 AM&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div message=&quot;But there are so many problems with it, shouldn&apos;t you expect an app to be good and improving?&quot; username=&quot;Xetera&quot; rolecolor=&quot;pink.600&quot; date=&quot;Today at 5:12 AM&quot; reactions=&quot;[object Object],[object Object]&quot; avatar=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;div message=&quot;That&apos;s the most ridiculous thing I&apos;ve ever heard.&quot; username=&quot;Definitely Not a Facebook Employee&quot; rolecolor=&quot;pink.700&quot; date=&quot;Today at 5:13 AM&quot; avatar=&quot;[object Object]&quot; reactions=&quot;[object Object]&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;h1 id=&quot;its-just-messaging-app-bro-why-feature&quot;&gt;&lt;a href=&quot;https://xetera.dev/#its-just-messaging-app-bro-why-feature&quot;&gt;It’s just messaging app bro, why feature?&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Every time someone says this, the WhatsApp product manager drools all over his office desk. Why would a messaging app be subject
to lesser standards you expect from other apps? I have 3 ideas for why I think this
might be the case.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;You haven’t experienced the features available in other, better, apps and don’t know there’s something else out there.&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This is certainly
possible, I didn’t have problems with WhatsApp before I discovered what Discord lets
you do, now it’s indistinguishable from SMS to me.&lt;/p&gt;&lt;ol start=&quot;2&quot;&gt;&lt;li&gt;&lt;strong&gt;You haven’t experienced the pain of the problems that exist in the current app.&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;No app is perfect, there’s
always something to fix and make life easier for the users. WhatsApp is certainly
in this stage and the problems it has are painfully obvious.&lt;/p&gt;&lt;ol start=&quot;3&quot;&gt;&lt;li&gt;&lt;strong&gt;You are over the age of 65.&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Somehow, this app found itself to be extremely popular with the older generation, which is great. I know my grandma and grandpa were baffled by Skype and thought they couldn’t do technology at all until they switched to WhatsApp and found it significantly easier and now they’re tapping away and I’m able to talk to them at a moment’s notice. Part of this coziness though, comes from the fact that WhatsApp just doesn’t change anything. Something that’s annoying enough for me to write a blog post on, is a feature in and of itself for older folks, and I of course have to recognize that.&lt;/p&gt;&lt;p&gt;So what are some of the things that WhatsApp is missing?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Channels&lt;/li&gt;&lt;li&gt;Stickers that don’t suck&lt;/li&gt;&lt;li&gt;Web app that doesn’t suck&lt;/li&gt;&lt;li&gt;Arbitrary 256 member limit for group chats&lt;/li&gt;&lt;li&gt;Getting your phone number (and probably your identity later) doxxed is a part of how the app works which is absolutely insane&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some of these are tied into my expectations of what I expect a chat app to do vs what some other expect it to do. It seems like for a lot of people, these things don’t matter.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Why does it matter if there are no channels if I’m just talking to my mom?&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;Why does it matter if there’s a group chat if I’m not in groups?&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;I trust everyone I use this app with so getting my phone number leaked isn’t an issue.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I understand where these arguments are coming from, you don’t have to use group chats on WhatsApp. I don’t have to use them either, but wouldn’t it be nice if there was just one app that was good that we could use for all types of chatting instead of one shitty one that sucks and another actual good one with all the features?&lt;/p&gt;&lt;h1 id=&quot;alternatives&quot;&gt;&lt;a href=&quot;https://xetera.dev/#alternatives&quot;&gt;Alternatives&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;So what do you think we should use instead? Allow me to introduce you to Discord!&lt;/p&gt;&lt;p&gt;Actually don’t, just go look it up yourself instead, but chances are you already know about it and it’s undisputably amazing.&lt;/p&gt;&lt;p&gt;Maybe you might claim that&lt;/p&gt;&lt;div p=&quot;4&quot; borderradius=&quot;md&quot; message=&quot;Yeah but like these apps don&apos;t really do the same thing, Discord isn&apos;t a chatting app.&quot; username=&quot;My last 2 brain cells&quot; rolecolor=&quot;green.300&quot; date=&quot;Today at 9:51 AM&quot; avatar=&quot;static/weSmart-5f610f7023447b5f7713a334719788f2.png&quot;&gt;&lt;/div&gt;&lt;div mb=&quot;4&quot; font-size=&quot;sm&quot; color=&quot;text.400&quot;&gt;I know it&apos;s a little ridiculous to do this joke the style of a Discord chat but someone on Discord unironically argued this with me.&lt;/div&gt;&lt;p&gt;Other than not storing messages on a server, —which I can guarantee the people you’re talking with, including yourself don’t actually care about— Discord a superset of WhatsApp in terms of features.&lt;/p&gt;&lt;p&gt;Another one you could be getting into is Telegram&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/bb9311e3b9dddead7bb7275862625726/d165a/telegram_logo.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:50%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQBBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHvT0mdBX//xAAYEAACAwAAAAAAAAAAAAAAAAABAgMgMf/aAAgBAQABBQI5Exav/8QAFhEAAwAAAAAAAAAAAAAAAAAAEBEh/9oACAEDAQE/AVR//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAAAERICH/2gAIAQEABj8CNc1//8QAGRABAQADAQAAAAAAAAAAAAAAAREAIFEx/9oACAEBAAE/IWjQrMW8E5I81//aAAwDAQACAAMAAAAQ9A//xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQMBAT8QUh2f/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAR/9oACAECAQE/EBATJ//EABoQAQABBQAAAAAAAAAAAAAAAAEAESAxQVH/2gAIAQEAAT8QoKlIdY5MkXdWv//Z&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/bb9311e3b9dddead7bb7275862625726/490da/telegram_logo.webp 250w,/static/bb9311e3b9dddead7bb7275862625726/e333e/telegram_logo.webp 500w,/static/bb9311e3b9dddead7bb7275862625726/54609/telegram_logo.webp 1000w,/static/bb9311e3b9dddead7bb7275862625726/61458/telegram_logo.webp 1400w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/bb9311e3b9dddead7bb7275862625726/0479a/telegram_logo.jpg 250w,/static/bb9311e3b9dddead7bb7275862625726/41099/telegram_logo.jpg 500w,/static/bb9311e3b9dddead7bb7275862625726/a2510/telegram_logo.jpg 1000w,/static/bb9311e3b9dddead7bb7275862625726/d165a/telegram_logo.jpg 1400w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/bb9311e3b9dddead7bb7275862625726/a2510/telegram_logo.jpg&quot; alt=&quot;telegram&quot; title=&quot;telegram&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;It too, has all the features WhatsApp has and addresses every single one of the issues above, with its cool sticker sets, 20k person group limit, hidden phone numbers and more. I feel comfortable using Telegram if Discord is indeed seen as a “not a chatting app”, which it totally isn’t but whatever.&lt;/p&gt;&lt;p&gt;So if all these apps have so many better features, why are people not using them? What’s the &lt;em&gt;real&lt;/em&gt; reason people are hanging onto WhatsApp, not wanting to let go? Simply put, it’s:&lt;/p&gt;&lt;div&gt;&lt;div color=&quot;rgb(120, 159, 115)&quot; time=&quot;9:18 AM&quot; messages=&quot;Hey Discord is really cool you guys,You wanna switch?&quot;&gt;&lt;/div&gt;&lt;div username=&quot;Billy&quot; number=&quot;+1 (234) 567-8910&quot; color=&quot;rgb(230, 159, 115)&quot; time=&quot;9:21 AM&quot; messages=&quot;Man it&apos;s just like,...,I&apos;m already using whatsapp,and so are all my other friends,.......,fuck off&quot;&gt;&lt;/div&gt;&lt;div username=&quot;John&quot; number=&quot;+42 (069) 1337-420&quot; color=&quot;#bd88eb&quot; time=&quot;9:23 AM&quot; messages=&quot;Lmaooo,Yeah dude we&apos;re not switching to Discord&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The truth is, if you’ve been using WhatsApp for a long time and all your friends are on it it’s kind of difficult to coordinate everyone to jump ship at the same time. That’s the vendor lock-in effect that WhatsApp has as its biggest feature…&lt;/p&gt;&lt;p&gt;So while it’s true that WhatsApp revolutionized the way we do instant messaging, it just hasn’t been keeping up. Just because you’re at the top doesn’t meaan you can stop trying because someone else (&lt;strong&gt;cough&lt;/strong&gt; discord, telegram &lt;strong&gt;cough&lt;/strong&gt;) will be catching up with features you should’ve implemented 5 years ago.&lt;/p&gt;&lt;div mb=&quot;6&quot;&gt;&lt;/div&gt;&lt;div title=&quot;Funny footnote&quot; icon=&quot;[object Object]&quot;&gt;&lt;div color=&quot;text.300&quot;&gt;While writing this post I sent something in WhatsApp that I had to delete later but accidentally ended up pressing &lt;div&gt;delete for me&lt;/div&gt; instead of &lt;div&gt;delete for everyone&lt;/div&gt; and completely lost the ability to delete it for everyone. Fuck this app AAAAAAAAAAAAAAAAAAAAAA.&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🎥 A night out at the theater]]></title><link>https://xetera.dev/a-night-out-at-the-theaters/</link><guid isPermaLink="false">https://xetera.dev/a-night-out-at-the-theaters/</guid><pubDate>Wed, 26 Aug 2020 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/a-night-out-at-the-theaters/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;If you’re a beginner at Javascript or you frequently help out beginners in online communities you know that the #1 thing that beginner programmers have problems with is Promises, or the concept of async programming in Javascript. Despite being a very useful construct in computer science, it’s not a very intuitive concept for most people learning programming for the first time.&lt;/p&gt;&lt;p&gt;If you’ve been linked here by me or someone else, please take the time to read this as &lt;code&gt;Promise&lt;/code&gt; is a word you’re going to be running into for as long as you’re writing Javascript code and it will haunt you the longer you keep running away from it.&lt;/p&gt;&lt;h2 id=&quot;why-do-promises-exist&quot;&gt;&lt;a href=&quot;https://xetera.dev/#why-do-promises-exist&quot;&gt;Why Do Promises Exist?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The most important thing about Promises you have to understand that promises are plans for the future, they’re not events that have been completed yet.&lt;/p&gt;&lt;p&gt;To better visualize what this might mean, imagine you’re running the part of the human brain responsible for making decisions. You have 3 functions you want to complete tonight called &lt;code&gt;watchMovie&lt;/code&gt;, &lt;code&gt;goHome&lt;/code&gt; and &lt;code&gt;goToSleep&lt;/code&gt;. These are functions that you want to call in the order you’re thinking of. You don’t want to sleep before you watch the movie and you definitely don’t want to get behind the wheel while you’re sleeping either.&lt;/p&gt;&lt;p&gt;Intuitively, the way most people would approach this problem would be something straightforward like:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;watchMovie()
goHome()
goToSleep()
&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;p&gt;However, these 3 are events that will take you 3 to 4 hours to complete and you, as the decision making part of the brain, have other human things to do like breathing, talking, thinking and any other activity you can think of. If you have to wait for the movie to finish before you can do any of these things again, you’re in for a lot of trouble.&lt;/p&gt;&lt;p&gt;In order to solve this issue you’ve decided that these functions shouldn’t completely prevent you from doing what you need to do. You should just be able to tell a part of your brain to focus on watching the movie. This way you can do things like get your nose to breathe while you’re watching the movie so you don’t die and get your mouth to tell your friend sitting next to you to stop talking so &lt;span style=&quot;font-weight:800&quot;&gt;hE CAN SHUT UP WHY IS HE TALKING DURING A MOVIE THIS ISN’T A CAFETERIA JUST LET ME WATCH THE THING IN PEACE!&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This also means that when you call these special functions, you’re actually just sending them off to different parts of your brain to be done later and moving on ASAP since you have other things to be scheduling. Because of that, running the earlier code:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;watchMovie()
goHome()
goToSleep()
&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;p&gt;Now means that you’re getting a part of your brain to watch a movie, get in your car to drive home and also sleep at the same time. Not what we were trying to do at all.&lt;/p&gt;&lt;h2 id=&quot;sequencing-different-actions-together&quot;&gt;&lt;a href=&quot;https://xetera.dev/#sequencing-different-actions-together&quot;&gt;Sequencing Different Actions Together&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;When you’re asking different parts of your brain to do these, you get a receipt or quite literally, a &lt;code&gt;Promise&lt;/code&gt;, back saying that the thing you wanted to happen will be done. You will also be notified when it’s completed so you can do other actions afterwards.&lt;/p&gt;&lt;p&gt;This is exactly the function of &lt;code&gt;.then()&lt;/code&gt; in Javascript. It lets you run a function only after a “future” action like watching a movie has finished. With that in mind, we can now chain watching a movie and going home like &lt;/p&gt;&lt;div text=&quot;the code snippet below&quot; class=&quot;text-green-300&quot;&gt;&lt;div&gt;If you&apos;re not familiar with &lt;pre style=&quot;display:inline&quot;&gt;() =&amp;gt; {}&lt;/pre&gt; I recommend looking into arrow functions and more modern ES6 syntax.&lt;/div&gt;&lt;/div&gt;:&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;watchMovie().then(() =&amp;gt; {
  goHome()
})
&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;p&gt;What if &lt;code&gt;watchMovie()&lt;/code&gt; returned some ideas about the movie and you wanted to go to sleep, dreaming about those? It might be tempting to do something like:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;let dreams = null
watchMovie().then(movieThoughts =&amp;gt; {
  dreams = movieThoughts
  goHome()
})
goToSleep(dreams)
&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;p&gt;But &lt;code&gt;.then()&lt;/code&gt; only runs when the movie has finished running and like we established above, you have to move on with the things you do so in this scenario you’re going to tell a part of your brain to watch a movie and then immediately tell another part of your brain to go to sleep with &lt;code&gt;null&lt;/code&gt; dreams since you didn’t wait for the movie to finish&lt;/p&gt;&lt;p&gt;Instead the correct way to do it would be&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;watchMovie().then(movieThoughts =&amp;gt; {
  goHome().then(() =&amp;gt; {
    goToSleep(movieThoughts)
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;p&gt;With this you’re waiting for the previous scheduled promise to finish before running the next ones.&lt;/p&gt;&lt;p&gt;This isn’t going to be a full tutorial on Promises, if you’re looking for more resources you can check out these resources.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://ui.dev/async-javascript-from-callbacks-to-promises-to-async-await/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;https://ui.dev/async-javascript-from-callbacks-to-promises-to-async-await/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://javascript.info/promise-basics&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;https://javascript.info/promise-basics&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And my personal favorite:&lt;/p&gt;&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom:56.25%;position:relative;height:0;overflow:hidden;margin-bottom:1.0725rem&quot;&gt; &lt;iframe src=&quot;https://www.youtube.com/embed/8aGhZQkoFbQ&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt; &lt;/div&gt;&lt;h2 id=&quot;reason-for-promises-in-real-javascript&quot;&gt;&lt;a href=&quot;https://xetera.dev/#reason-for-promises-in-real-javascript&quot;&gt;Reason for Promises in Real Javascript&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The reason why Javascript behaves this way by default and why a language like Python or Java doesn’t is because even though Node is a big player in server side technology these days, Javascript was historically meant to only be run in a browser. And in a browser, Javascript is tasked with re-rendering the HTML on your screen and scheduling other things about web pages. If every time you make a request, Javascript has to wait 1+ second for the request to finish, much like how your brain wouldn’t be able to breathe, Javascript won’t be able to paint changes to the screen like animations, button clicks, typing and so on, leading to terrible user experience.&lt;/p&gt;&lt;p&gt;Promises are a confusing concept so if you’re still confused, don’t worry too much about it. This idea is going to click as you keep working with it more and more.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🤡 Every technology deserves to be memed]]></title><link>https://xetera.dev/tech-memes/</link><guid isPermaLink="false">https://xetera.dev/tech-memes/</guid><pubDate>Fri, 17 Jul 2020 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/tech-memes/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Ben Awad, a tech Youtuber I’ve been following for a while who mocks &lt;/p&gt;&lt;div text=&quot;Angular&quot; class=&quot;text-red-300&quot;&gt;A Javascript framework made by Google. It&apos;s not as popular as others, but still widely used around the world.&lt;/div&gt; and its users as a running joke on his Youtube channel and Twitter recently released a video explaining how what he’s been doing might be harmful after receiving criticism from the &lt;div text=&quot;React&quot; class=&quot;text-blue-300&quot;&gt;A Javascript framework like Angular, but is more popular and less opinionated.&lt;/div&gt; god himself.&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom:56.25%;position:relative;height:0;overflow:hidden;margin-bottom:1.0725rem&quot;&gt; &lt;iframe src=&quot;https://www.youtube.com/embed/Ap1CzrIBIVw&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt; &lt;/div&gt;&lt;p&gt;In the video and the discussion on Twitter, the 2 ideas of making low effort jokes that get tiring over time and making &lt;em&gt;harmful&lt;/em&gt; jokes seem to be conflated and I’ll try to address that later on.&lt;/p&gt;&lt;p&gt;I believe the attitude that jokes about Angular or any other technologies is harming that community is problematic for different reasons but before you agree with me, I want to preface this by saying this isn’t a political take. I’m not “tired of snowflakes” and if you agree with me because you want everyone to stop being too sensitive, you should probably stop reading now.&lt;/p&gt;&lt;h2 id=&quot;muh-technology&quot;&gt;&lt;a href=&quot;https://xetera.dev/#muh-technology&quot;&gt;Muh technology&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Over the past 2 years I’ve had the privilege of moderating a programming community on &lt;/p&gt;&lt;div text=&quot;Discord&quot; class=&quot;text-indigo-300&quot;&gt;A chat platform like WhatsApp or Skype that was originally aimed towards gamers but has since grown way past gaming.&lt;/div&gt; that’s now grown to over 50k members as well as being a member of a couple other ones. Undoubtedly, I learned a lot about programming during the years but I also learned a lot about how people view and talk about it.&lt;p&gt;&lt;/p&gt;&lt;p&gt;There’s unfortunately a large chunk of programmers in these communities ranging from complete beginners to seasoned veterans who view their favorite languages and frameworks not as tools designed for specific tasks, but as lifelong companions. Watching programmers argue about whether Python is a “good beginner’s language” feels more akin to listening to your dad and uncle shout at each other across the living room during a soccer tournament rather than a reasonable discussion between experts (which is why we no longer allow discussions about what language beginners should start with anymore).&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:569px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/05dcc1e43dee1a2cd36a14f6f242f807/854dc/beginner_language.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:68%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACF0lEQVQoz32SXU8TQRSG+Q2aqMXIXZsoBNOP3fncmTmzMzvb3e22Ag0QiBYhIqYhckW4KAaNYuRGb0z0xmj8EcZLf5nZbUmKVpP34lycZ857zjtzzcaSWWrvVvZ3KnuDyt7jm0+2FgacWSYN4bqFAp/If2lOoiZmSoWxtomOUm0TFcUu61rXsXGedla1TT0sEFU+kYhKNA1jhrLG2kn1xXFtdFwdHddGJ9VT6+c+l5hqDwsPixYKpuVhMYHfPGMDvXW2/O5l422h+vnr5kVPbaiorU2mdCxLU2DayiRgEm0SwvWYn1MgKNeEACFAmaZUEwZUaC4sV1FQSkCponACIsJgMtlvLLp72eH80cH88Omt4fDO4cHC0IpcGIcptHz+h+crtuuLdzFIt9GTvVjkLltdy1b6/c2Hea/vk0lTeaRZB3v+6vNu4/DLtW9fb3z/cPtjgCLMwMey4fH/hDSBLz79it36g3A9k31HuoQAYgozQFSNVQ6cFH/lbKyoR0mt1651ed14TCCiPHQZj889LJrl5jPg96d7q3Rtu7rzqLa7gjchTkObCnBSOxW2tUklODAJhPEMWEgZBNaqXEDMQhPIIhsuTKAiCQUfSKvCttQF7OGr8PJ2un//6Mf1n2fVc6RAQDyOcXpbj0ifSsxgLMIvcyZpj4IJbaZtYbj80h1tU1MWxnWMy8Ioi+IcTGJc0WbjDi6f/g19xNpb1VV/mQAAAABJRU5ErkJggg==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/05dcc1e43dee1a2cd36a14f6f242f807/490da/beginner_language.webp 250w,/static/05dcc1e43dee1a2cd36a14f6f242f807/e333e/beginner_language.webp 500w,/static/05dcc1e43dee1a2cd36a14f6f242f807/2c052/beginner_language.webp 569w&quot; sizes=&quot;(max-width: 569px) 100vw, 569px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/05dcc1e43dee1a2cd36a14f6f242f807/63868/beginner_language.png 250w,/static/05dcc1e43dee1a2cd36a14f6f242f807/0b533/beginner_language.png 500w,/static/05dcc1e43dee1a2cd36a14f6f242f807/854dc/beginner_language.png 569w&quot; sizes=&quot;(max-width: 569px) 100vw, 569px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/05dcc1e43dee1a2cd36a14f6f242f807/854dc/beginner_language.png&quot; alt=&quot;discussion about good beginner languages&quot; title=&quot;discussion about good beginner languages&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;We spend a lot of time around our favorite tools, setting up &lt;/p&gt;&lt;div text=&quot;dotfiles&quot; class=&quot;text-green-300&quot;&gt;A collection of configurations saved online to allow devs to reinstall their preferred tools quickly on new machines.&lt;/div&gt; to make sure we’re not separated from our preferred technologies and working on getting better at a single programming language instead of hopping between many different ones to learn more. While none of these are unreasonable, it gets us more attached to our preferences and it leads to conflict in tech communities combined with other factors like:&lt;p&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Developers often become confident in their opinions, choices and preferences as they improve, sometimes becoming &lt;em&gt;too&lt;/em&gt; confident.&lt;/li&gt;&lt;li&gt;Feeling like you’re a part of a community of unique people and seeing yourself as an Angular developer feels nicer than being just any other developer who uses whatever language is fit for the job.&lt;/li&gt;&lt;li&gt;People are just very impressionable in general.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;That last one resonates quite a bit with me. When taking my second programming class in a community college, I would often hear people who I knew were beginners say things like “Yeah man Python’s actually a kid’s language, C++ is much harder and just better” while the people around him who’ve also never used any language other than the one we were learning in class nodded in agreement. This was after I’ve already been exposed to the same kinds of arguments online so it wasn’t much of a shock to me but still frustrated me.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/599bde65de832b11f9915d7d699cf627/e5166/disappointed_but_not_surprised.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:71.6%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABAAB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwAC/9oADAMBAAIQAxAAAAE2lSmg20f/xAAZEAADAQEBAAAAAAAAAAAAAAABAgMAEhT/2gAIAQEAAQUCnIFDAZ15Zab0MQX3/8QAFREBAQAAAAAAAAAAAAAAAAAAAhD/2gAIAQMBAT8BU//EABYRAQEBAAAAAAAAAAAAAAAAAAEAIf/aAAgBAgEBPwECy//EABoQAAICAwAAAAAAAAAAAAAAAAABETICECL/2gAIAQEABj8CUs5ZBVapif/EAB0QAAIBBAMAAAAAAAAAAAAAAAERACExYXFBUdH/2gAIAQEAAT8hKgkbYilDZMaMCuonh04VtAMCBfpP/9oADAMBAAIAAwAAABAc3//EABcRAAMBAAAAAAAAAAAAAAAAAAABEWH/2gAIAQMBAT8Qaomn/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAh/9oACAECAQE/EAGR/8QAHxABAAIBAwUAAAAAAAAAAAAAAQARITFBcVFhodHw/9oACAEBAAE/EBxRtA3yxFMSm427BMg/U3rzMNPodY4rQqqJb5+T2n//2Q==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/599bde65de832b11f9915d7d699cf627/490da/disappointed_but_not_surprised.webp 250w,/static/599bde65de832b11f9915d7d699cf627/e333e/disappointed_but_not_surprised.webp 500w,/static/599bde65de832b11f9915d7d699cf627/54609/disappointed_but_not_surprised.webp 1000w,/static/599bde65de832b11f9915d7d699cf627/71b6b/disappointed_but_not_surprised.webp 1200w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/599bde65de832b11f9915d7d699cf627/0479a/disappointed_but_not_surprised.jpg 250w,/static/599bde65de832b11f9915d7d699cf627/41099/disappointed_but_not_surprised.jpg 500w,/static/599bde65de832b11f9915d7d699cf627/a2510/disappointed_but_not_surprised.jpg 1000w,/static/599bde65de832b11f9915d7d699cf627/e5166/disappointed_but_not_surprised.jpg 1200w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/599bde65de832b11f9915d7d699cf627/a2510/disappointed_but_not_surprised.jpg&quot; alt=&quot;disappointed but not surprised&quot; title=&quot;disappointed but not surprised&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h2 id=&quot;dont-fall-in-love-with-your-tools&quot;&gt;&lt;a href=&quot;https://xetera.dev/#dont-fall-in-love-with-your-tools&quot;&gt;Don’t fall in love with your tools&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;So what does any of this have to do with making fun of technologies? I think tool attachment and advocacy is a serious problem in tech communities that prevents us from improving as developers and very often leads to people being defensive about tools they like and aggressive towards ones they don’t. There’s a very interesting &lt;a href=&quot;https://www.perl.com/pub/2000/12/advocacy.html/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;article&lt;/a&gt; by Mark-Jason Dominus that approaches the same problem through the perspective of Perl, a language that’s fallen out of favor significantly among most developers by now, 2 decades after the article was written, but still had the zealots making the same arguments at the time.&lt;/p&gt;&lt;p&gt;Because of this, when I see replies like&lt;/p&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;dark&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Honestly man, this is not cool. It’s been kind of depressing to see you bash anything that starts with an A. I’m not the one to tell others about low effort posting but this is just tired.&lt;/p&gt;— Dan Abramov (@dan_abramov) &lt;a href=&quot;https://twitter.com/dan_abramov/status/1284512869418246152?ref_src=twsrc%5Etfw&quot;&gt;July 18, 2020&lt;/a&gt;&lt;/blockquote&gt;&lt;p&gt;I say let the kids play Dan, let’s make fun of Angular and React and anything else. Let’s show that as developers, we don’t to create an identity based around tools. Technologies come and go and we don’t need to form emotional attachments to them, a joke or criticism aimed towards the tool of your choice isn’t an insult towards who you are. You can be a proud Vue developer or a carrot farmer, it just doesn’t matter because at the end of the day, you’re a developer like me. Sure it feels good to view yourself as a member of a community of developers who use the same tools as you, but you can do that without feeling like you have to pledge an allegiance to it.&lt;/p&gt;&lt;p&gt;I believe that becoming more comfortable with jokes thrown around at different technologies will prevent new, impressionable developers from blindly taking sides with the ones they personally enjoy using if they see that devs make fun of the idea of a single, superior tool.&lt;/p&gt;&lt;h2 id=&quot;online-circlejerks&quot;&gt;&lt;a href=&quot;https://xetera.dev/#online-circlejerks&quot;&gt;Online circlejerks&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I will admit, however, that the one problem with running amok with jokes is that when making them, the fact that they’re jokes has to be communicated clearly. It’s possible that jokes like these might still devolve into &lt;/p&gt;&lt;div class=&quot;text-orange-300&quot; text=&quot;circlejerks&quot;&gt;&lt;div&gt;&lt;p class=&quot;mb-0&quot;&gt;When multiple people on the internet who have a shared interest or ideology get together to congratulate each other for having the opinions they do.&lt;/p&gt;&lt;sub class=&quot;text-gray-500 m-0&quot;&gt;Please just trust me on the definition and don&apos;t Google this word&lt;/sub&gt;&lt;/div&gt;&lt;/div&gt; where people repeat the same old incorrect things that are no longer meant to be funny and end up having the opposite intended effect.&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/a9475d8f39fa0fb56fb7de3087d2668a/d165a/parrots.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:75.2%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAQL/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/9oADAMBAAIQAxAAAAHvZrGTnjRR/8QAGxAAAgIDAQAAAAAAAAAAAAAAAQIAEgMRISL/2gAIAQEAAQUCTIIxuH4yH1aMdz//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFH/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHBAAAQQDAQAAAAAAAAAAAAAAAQAQERIhIlFx/9oACAEBAAY/AotYcWwAbAhet//EABoQAQADAQEBAAAAAAAAAAAAAAEAESExQWH/2gAIAQEAAT8hVdnQpUuBTdIFDkHg+tY0T1HvksaGZP/aAAwDAQACAAMAAAAQGP8A/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARQf/aAAgBAwEBPxBDkNNC/8QAGBEAAwEBAAAAAAAAAAAAAAAAAAERIVH/2gAIAQIBAT8Qa4WYf//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESFBMVGRobH/2gAIAQEAAT8QdtRFZHYnR7gkyEDXGpS96TRsXkj5YecrKcEX9qKdpGXeWf/Z&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/a9475d8f39fa0fb56fb7de3087d2668a/490da/parrots.webp 250w,/static/a9475d8f39fa0fb56fb7de3087d2668a/e333e/parrots.webp 500w,/static/a9475d8f39fa0fb56fb7de3087d2668a/54609/parrots.webp 1000w,/static/a9475d8f39fa0fb56fb7de3087d2668a/61458/parrots.webp 1400w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/a9475d8f39fa0fb56fb7de3087d2668a/0479a/parrots.jpg 250w,/static/a9475d8f39fa0fb56fb7de3087d2668a/41099/parrots.jpg 500w,/static/a9475d8f39fa0fb56fb7de3087d2668a/a2510/parrots.jpg 1000w,/static/a9475d8f39fa0fb56fb7de3087d2668a/d165a/parrots.jpg 1400w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/a9475d8f39fa0fb56fb7de3087d2668a/a2510/parrots.jpg&quot; alt=&quot;parrots&quot; title=&quot;parrots&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;mx-auto&quot; style=&quot;max-width:650px&quot;&gt;&lt;p class=&quot;text-gray-400 text-sm&quot;&gt;A rare image of a highly sophisticated discussion about languages in an online programming community.&lt;/p&gt;&lt;/div&gt;&lt;p&gt;I definitely don’t want to encourage this, but I think that if people see that other programmers don’t take themselves and their tools &lt;em&gt;too&lt;/em&gt; seriously, this will not happen.&lt;/p&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;dark&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;I’m serious. I’ve seen a variation of tweets that are all like “angular bad” over the last few days and I think this lazy attempt at humor makes our community look like jerks and creates artificial division.&lt;/p&gt;— Dan Abramov (@dan_abramov) &lt;a href=&quot;https://twitter.com/dan_abramov/status/1284516811036397569?ref_src=twsrc%5Etfw&quot;&gt;July 18, 2020&lt;/a&gt;&lt;/blockquote&gt;&lt;p&gt;I can understand where Dan is coming from with this. Like I said before, jokes can get out of hand and turn into something harmful and it’s definitely a good idea to consider that. I just don’t know if artificial division is a valid concern, it’s not like joking about programming tools is the same as joking about one’s gender or race. It’s not what makes you you and there’s definitely merit in separating your feelings from your tools.&lt;/p&gt;&lt;p&gt;Coming back to the idea of conflating bad jokes with harmful ones. I think, yes, Ben’s Angular jokes probably got a little bit too out of hand and it ended up being more annoying than funny for some (though I personally still enjoy them sorry not sorry). Dan’s comment of &lt;code&gt;low effort posting&lt;/code&gt; is definitely valid criticism. I just don’t think it was necessarily harmful towards any particular group that needs protection.&lt;/p&gt;&lt;p&gt;So keep poking fun at different technologies and being funny. When you’re at the receiving end of these, you need to remember that at the end of the day you are who you are and not what you use. Consider everything with a critical mindset and don’t take yourself too seriously.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[💀 The terrible fate of reduce]]></title><link>https://xetera.dev/the-terrible-fate-of-reduce/</link><guid isPermaLink="false">https://xetera.dev/the-terrible-fate-of-reduce/</guid><pubDate>Tue, 14 Jul 2020 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/the-terrible-fate-of-reduce/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;I recently came across this video on youtube that a friend linked talking about the problems with reduce:&lt;/p&gt;&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom:56.25%;position:relative;height:0;overflow:hidden;margin-bottom:1.0725rem&quot;&gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/qaGjS7-qWzg&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt; &lt;/div&gt;&lt;p&gt;and it gave me some conflicting thoughts which got me thinking. Why is it that the tool that plays such a crucial part in functional programming so hated by experienced developers? Of course, debating menial stuff is a programmer’s favorite pastime but the &lt;code&gt;reduce&lt;/code&gt; argument seems to be popping up every single time someone suggests using reduce to solve a problem.&lt;/p&gt;&lt;p&gt;Before continuing, lets briefly go over what &lt;code&gt;reduce&lt;/code&gt; actually is&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;function sumNumbers(numbers: number[]) {
  return numbers.reduce((sum, num) =&amp;gt; sum + num, 0)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here, &lt;code&gt;reduce&lt;/code&gt; simply takes a list of numbers and goes over them, while changing the accumulator for the next iteration. This is, of course, an oversimplified example but the basic idea is that you have a generic list of items, and there’s an accumulator of some data type that is updated in each iteration. In that case, what’s so bad about it?&lt;/p&gt;&lt;h2 id=&quot;hate-the-player-not-the-game&quot;&gt;&lt;a href=&quot;https://xetera.dev/#hate-the-player-not-the-game&quot;&gt;Hate the player, not the game&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;From the video and the discussions I’ve had with people online, it seems like a lot of the hate that’s directed towards reduce is that it’s easy to abuse. There are a lot of ways to use reduce in ways it wasn’t meant to be used, though you could say that it’s possible to blame a lot of different things with that reasoning. It’s not the function itself that’s problematic, it’s just ways that people use it. On one hand that’s true and doesn’t make reduce itself bad, but on the other, programmers read other programmers code and the way people use tools affects the way it’s viewed as well.&lt;/p&gt;&lt;p&gt;But the story of &lt;code&gt;reduce&lt;/code&gt; starts way before Javascript, so lets take a look at the origins of reduce itself and why it feels like a monstrosity to developers.&lt;/p&gt;&lt;h2 id=&quot;functional-origins&quot;&gt;&lt;a href=&quot;https://xetera.dev/#functional-origins&quot;&gt;Functional Origins&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Reduce is actually somewhat of a more modern name for the same concept found in many functional languages referred to as a &lt;code&gt;fold&lt;/code&gt;. Like many other popular features like lambdas and higher order functions, the idea of folding is borrowed from languages like Haskell and Lisp because they are very convenient to use in those languages.&lt;/p&gt;&lt;p&gt;However, I want to argue that the convenience of functions and concepts in paradigms aren’t solely based on the merit of the idea itself, but are closely tied to how they fit within the paradigm they’re used in.&lt;/p&gt;&lt;p&gt;Consider the &lt;code&gt;Array.prototype.flat&lt;/code&gt; rewritten in Typescript that’s written using reduce&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;function flat&amp;lt;T&amp;gt;(arrays: T[][]): T[] {
  return arrays.reduce((all, arr) =&amp;gt; all.concat(arr), [])
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It’s not too bad, I would argue reduce is the right tool for a function like this, and now the same function written with a regular for loop&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines:true}&quot;&gt;function flat&amp;lt;T&amp;gt;(arrays: T[][]): T[] {
  const out: T[] = []
  for (const arr of arrays) {
    out.push(...arr)
  }

  return out
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You could argue that the for loop version is longer-ish or that the reduce doesn’t give you any benefit and both of those would be reasonable thoughts. If reduce is such a “good” concept, why is this a controversial argument? Higher order functions are a good concept and we don’t spend nearly as much time debating those.&lt;/p&gt;&lt;p&gt;The answer to this is in how JS and other popular languages try to fit features that don’t work well in non-functional paradigms in their language.&lt;/p&gt;&lt;h2 id=&quot;reduce-sucks-but-fold-is-king&quot;&gt;&lt;a href=&quot;https://xetera.dev/#reduce-sucks-but-fold-is-king&quot;&gt;Reduce sucks but fold is king&lt;/a&gt;&lt;/h2&gt;&lt;pre&gt;&lt;code class=&quot;language-hs&quot;&gt;flat :: [[a]] -&amp;gt; [a]
flat = foldl (++) []
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is the Haskell version of the same function above and it looks… comical in comparison. Some questions that may arise in reader’s mind when looking at this example are:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;How is this so much shorter than the JS version?&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;flex-row items-center flex&quot;&gt;
  What the hell is going on here?
  &lt;img src=&quot;https://xetera.dev/../../assets/emotes/asanaconfused.gif&quot; height=&quot;30&quot; class=&quot;ml-2&quot; alt=&quot;sana confused&quot;&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;We’re essentially doing the exact same thing as the first one JS example&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-hs&quot;&gt;flat :: [[a]] -&amp;gt; [a]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We’re stating that a &lt;code&gt;flat&lt;/code&gt; function takes an input of 2 nested arrays and returns a singly nested array:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-hs&quot;&gt;flat = foldl (++) []
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And that flat is defined as a reduce of the input where the function is &lt;code&gt;(++)&lt;/code&gt; (array concatenation) and the initial value is &lt;code&gt;[]&lt;/code&gt;, an empty array.&lt;/p&gt;&lt;p&gt;The reason why this is so much shorter than the JS counterpart doesn’t actually have anything to do with Haskell specific syntax. It’s possible to write reduce in this exact way in Javascript&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{lines: true}&quot;&gt;const flat = arr =&amp;gt; reduce(concat)([])(arr)
// or we can reduce this definition to just
const flat = reduce(concat)([])

flat([
  [1, 2, 3],
  [4, 5],
])
// [1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But we choose not to because it doesn’t feel natural in JS (Also Typescript, as of today with 3.9 isn’t able to infer types of curried functions very well but that’s a different story). If you’re an epic category theorist this is fine but it can be a problem if your coworker submits a pull request with code above and you can’t help but feel like he’s challenging you to a high IQ competition. It seems like a big part of the debate revolves around people who are used to a functional style trying to shoehorn functional patterns into every language they use vs js programmers who are either not familiar with FP or don’t want to use it in JS.&lt;/p&gt;&lt;h3 id=&quot;so-what-do-we-do&quot;&gt;&lt;a href=&quot;https://xetera.dev/#so-what-do-we-do&quot;&gt;So what do we do&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;It seems like the syntax alone does not solve this problem. Fold/Reduce seems to be a good concept that works in the right languages, but not so much in javascript.&lt;/p&gt;&lt;div background=&quot;bgSecondary&quot;&gt;&lt;div justifycontent=&quot;space-between&quot; py=&quot;4&quot; alignitems=&quot;center&quot; flexdirection=&quot;col,,row&quot; borderradius=&quot;md&quot; color=&quot;text.400&quot; font-size=&quot;md,,lg&quot;&gt;&lt;div alignitems=&quot;center&quot; mb=&quot;0&quot;&gt;&lt;div mr=&quot;3&quot; mb=&quot;0&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 576 512&quot; height=&quot;1em&quot; width=&quot;1em&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div as=&quot;h3&quot; my=&quot;0&quot; font-weight=&quot;black&quot; color=&quot;inherit&quot; font-size=&quot;inherit&quot;&gt;Warning&lt;/div&gt;&lt;/div&gt;&lt;div font-weight=&quot;black&quot; my=&quot;0&quot; color=&quot;inherit&quot;&gt;Opinion Ahead&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;I think reduce is fine to use, don’t try to use it like you’re writing Haskell but the idea is valuable. If your code is too smart, that’s a problem that goes beyond just reduce. Reduce is innocent.&lt;/p&gt;&lt;p&gt;I also think Javascript should have put the seed value of reduce as the first argument, not the second. In functional languages with currying, it’s valuable to have the seed value as the second argument because your code is more modular when you leave the data to be inputted last so you can pass it as an argument later, but this has no use with JS. It would’ve been much better to have reduce that goes:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function sum(nums: number[]): number {
  return number.reduce(0, (all, num) =&amp;gt; {
    return all + num
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This way the initial value and the function are all in the same place and you don’t have to go up and down the function call to see what you’re working with.&lt;/p&gt;&lt;p&gt;In essence, just be responsible with your code and it doesn’t matter whether you’re using reduce or the fancy function from next hot new paradigm.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🧠 Learning for fun and profit]]></title><link>https://xetera.dev/learning-for-fun-and-profit/</link><guid isPermaLink="false">https://xetera.dev/learning-for-fun-and-profit/</guid><pubDate>Thu, 09 Jul 2020 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/learning-for-fun-and-profit/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;You’re a 19 year old highschool graduate, unsafisfied with life and with no desire to do anything, partially because you don’t know what’s out there, but also because you see that you get bored of everything you’ve tried to learn in the past. You feel like you’re a curious person but not a hardworker because you’ve never seen yourself succeed in things other people work hard to get better at, especially not school. The one thing you &lt;em&gt;do&lt;/em&gt; love is gaming but you’re not even successful at that despite pouring hundreds, no.. &lt;em&gt;thousands&lt;/em&gt; of hours into it. Knowing this about yourself, you think “maybe I’m just bad at learning”, and proceed to log back into World of Warcraft for the millionth time to forget about your problems.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/d5a6a38794a54a1461c74c96c0543893/9fafa/wow_screenshot.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:50.8%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACPElEQVQozwXB227SYAAA4B7pevp7PpfSFkopsLZQIIMxYIxDxuY00x2iZJrMmExcNLrF6JbMF/DKeOcDeOdufQNvvPGJ/D6IDPNiaICiQFiAcATcltDIxPo+dpxi5+Mnv277Pz9yZz2kE5BbEZ65aOrArRAeNPijCWTF9miYTxuaFcpKRdGqBp/Z3Nill0P01fzqz9c3/+5zN89zjztwx0V6ETxO0O2MeDbGL59CXsydPKA0X2AtjrFY2ma4OicODPYwEd/vL3/fXf29x2+v0ZMuEjtIWsDaJbxboc7nxLcrCDJ4wrBKbplghBzDwRwJGzSeyegiJl48cj4vGz++kB9W8KyK+ApmK4RjKHWXO2zkbg4gPC8rkb3ZDykeEDwNszlMpohYdO6ORu9Wg51t/XqJXZ8hOxXcVihZJ1TDKHvyIkVXUwgqG1zDbWympM5RmoBzADJYqa0ny510q5U2KpW9Afn2EzLsIjpYk1RCUjXH43sJdjqCzN28P/CqfshrChBFSmFUT+y0vY2Rp8dB1AxrixK5N0HabUSjc4KAkkIxy6s9D0p8KD6wmvNSvZ8An6FVktIpuSZtp8HpLFzfCNqdejB1wFih6sqaCWiRXwOgmNaqs9icu1C0q7lDJ2gVgM+wFs0VWC1TBpfrF997s6N6q9tsTtXqQnA6EmsxQCYFk9rc8ibLZOO1C2UTqdQ2I7egFDROk3iTFypi8Vgvr/R0FK3XqmIAhIQFPkvpFCsCWpKGU/fhRXP3pf0f7F9f9yA+CgQAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/d5a6a38794a54a1461c74c96c0543893/490da/wow_screenshot.webp 250w,/static/d5a6a38794a54a1461c74c96c0543893/e333e/wow_screenshot.webp 500w,/static/d5a6a38794a54a1461c74c96c0543893/54609/wow_screenshot.webp 1000w,/static/d5a6a38794a54a1461c74c96c0543893/de0ca/wow_screenshot.webp 1500w,/static/d5a6a38794a54a1461c74c96c0543893/d6919/wow_screenshot.webp 1565w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/d5a6a38794a54a1461c74c96c0543893/63868/wow_screenshot.png 250w,/static/d5a6a38794a54a1461c74c96c0543893/0b533/wow_screenshot.png 500w,/static/d5a6a38794a54a1461c74c96c0543893/00d43/wow_screenshot.png 1000w,/static/d5a6a38794a54a1461c74c96c0543893/aa440/wow_screenshot.png 1500w,/static/d5a6a38794a54a1461c74c96c0543893/9fafa/wow_screenshot.png 1565w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/d5a6a38794a54a1461c74c96c0543893/00d43/wow_screenshot.png&quot; alt=&quot;World of Warcraft&quot; title=&quot;World of Warcraft&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Future in shambles but that loadout popping off though&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;6 months after starting a chemistry degree you realize you hate it and drop out, losing any little certainty you had about the future of your life. Chemistry was your strongest subject so now you’re left with absolutely nothing else to do. You eventually decide that you’re going to sign up for a computer science degree and you come to this brilliant conclusion by remembering that you’ve tried programming 3 times before and hated it every time but maybe it’ll be ok because you like playing games on the computer and programming is also done on the computer…? Not the smartest choice you’ve made, but a choice nonetheless.&lt;/p&gt;&lt;p&gt;Fast forward a week or so, and you’ve decided that you might as well get started and look up some programming stuff and you remember hearing that Python is a good beginners language, so you figure you might as well get started with it. You pick up Zed Shaw’s awful &lt;a href=&quot;https://learnpythonthehardway.org/python3/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;Learn Python the Hard Way&lt;/a&gt; and start reading through a fairly bland book.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot;&gt;print(&quot;Hello World&quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool, you wrote your first line of code but it wasn’t all that impressive and you get bored about an hour in, but this is a kind of boredom you haven’t felt before. You don’t feel an urge to close the tab and start a new game of League, you want to keep writing code. It is here that you do something &lt;em&gt;unspeakable&lt;/em&gt;, something so outrageous that it makes all highschool teachers and college professors around the world turn in their metaphorical graves. You decide to skip ahead and do something more interesting instead of continuing to learn the basics. This isn’t how you’re supposed to do things, maybe you’re just bad at learning.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:128px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/f94659eb05584b3ce59a277ad281867d/750d2/pythonk.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:100%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFRUlEQVQ4y03UaWwUZRgH8Gc3Gq2UGMUYkKDxoDEt3Za2O+/O7My2EIl+0cREMTHxCyZqgoofVKDHzIqgSClVxKp4gCegpWqkYGkj9Nid7bFtbSGCEa94ou3szO7OsTvzPGbWRp3kyXz75f/+3wPqZgiiMwRCGkEYwYCYoiD/AoHwPN3O78BPmWL8wOSMxWTdZLL+LVOMDyPxPGOyAUwxAqEnLgJr0eDfrwTOEggTGBA9gugRAn57cWP9kxco9NBp4lrniMkZ4tq0f4fJOjElexeL54DFs0HW+j8w+rAO0XGE6E8EwpR3c2RWX8lvw0TF3V10zU0Re/WmWY/Fs8i1zSOTM56ftoQqRnfo6TlY/5wa/KTnOSimRShOSgDC3iLw3c6lQppAmKbHhWk0+XY6H97yC9VsTGLkWQcj2xzk2jTkZM1Hi/+A2cPhzd8BrKXA/t3PgJ2KBemvtQBV1VMQXvc78GeKIKS8e4QZoho56VWu78FVD5ygyvu6cdWGPuLa5v2l+/ACaBxet3kCYB+B3Vvlg2AOiQEIP/onsBZjI9ueTfNJ/FmYIKpTzno1TyWpdtc41r41SQ3931HkiEXcVg2Zork+GFZyhyhd/5Klxs7ZqjTmjMbusVUJgCnZdX7pfG+B/HR8ykMhSRSdIYrOEgpfEvIfIbJ2A7lWDSPyvBtpmyNeyRymVMNpMyGRlZDIViW3MCpVAduaOco6DBJmyebT6AmTRPwUIj+FxJ8qINc6X+SennO5Fs1lslYMy3ox1Fqgqjjtoq/qTuYTjWQlxLydlMhJSR3ANWculMBp8vgJJD6NKEwgRqc9jJ4qUETx+9IoopQ6JEn+je6PJ9wvX7r3gNe7MmMOi2SrMddK+H9pDJis5/xO+IEiCmeJhDQinyaqmyYKnaJvQputrpoWc/+qZmdfZTO+rLavmS90BsnsvIz09iso++oStE5xaKkxspNiDpiiG1yLRmynjnx/ASNpInHSte6b+J6Oju38jcYrTtB4XT+lV/fRYMWJwt5LDX1POemdi73si+Vo7LqMcgeXo51q9EHNT/g1J2vEWrRiRJ6n0C5vaHZsw0f5ZIwwwZHfUX5EIlNtotwAI/3FK8noLMdsZzllO8vR2LMIs/uucq0hnuxUbNC/jwdZW4aYrOX8juq3modotLLP37l8Ila0k5JrpxpdM9Xk5o7XunrHIsy0l5HeXoYlcHeZm33lasvv0BmNxYHFc6uZrCMr3VGNGhSzl8YbBv7ZPcm1EhKa3RXkHbiWvP1X+YP43lJy3l+Bxp5SSjKPVZM91vSnM8Jf519uf+5giv4BU4yeBsV+jEa5QTMRK4GOKuHc2ytoYNMi+qJ5KfbtuBGPd1ThN103oNVxeSF/6MbjzuTaAwU1yjkp/2DHs4FIPAehLTrUb/4VHnxhAGxVGvWXYCXEEqgPiZR8s5YSb9TS1Lu1NPxGrXfh5eVkdZbZ+deWrLCOVUPx2zvBGY0FgN9eKD1Bd++YDl7/yMUAEYCzAPr9WQkR7aSI9FUTZgej2B2/xfu9jydS2Yyxu2zW3Ls4bCoAdk/FJYWJNQANrRloaNHg855tcPLjR8EcavATqgsJbR/Nj4iI4404ebDGbbohaPV13Ep0/rZ3ACBgvbPscmcLgNNVDvnB8H/vYnFMBCclBf0enFHpTluVfMxPSQtpyRwR6cfPwpQdil7EiRij4Xoo0jZwuhaDs28RzDX/54E7LsL510NgDosBR5WgOB5b6aSknbYqDdtJ6S87Kf3hqNIAnVnTRufWLqOpRsD+6mBhPSyA5eA+A/A34I69kxJ4KjMAAAAASUVORK5CYII=&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/f94659eb05584b3ce59a277ad281867d/59bed/pythonk.webp 128w&quot; sizes=&quot;(max-width: 128px) 100vw, 128px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/f94659eb05584b3ce59a277ad281867d/750d2/pythonk.png 128w&quot; sizes=&quot;(max-width: 128px) 100vw, 128px&quot; type=&quot;image/png&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/f94659eb05584b3ce59a277ad281867d/750d2/pythonk.png&quot; alt=&quot;pythonk&quot; title=&quot;pythonk&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;A day or two go by and after making a coinflip and number guessing game you’re bored once again even though working on them was enjoyable. You’ve recently been spending a lot of time on Discord and realized that the music bot you’ve been running with your friends is written in Python! You go through the source code to see how it works and by some miracle you somehow figure out how to add a new command. It’s not pretty, and &lt;a href=&quot;https://gist.github.com/Xetera/522a615bc065fbe37490527c7bc3f679&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;definitely cursed&lt;/a&gt; but you managed to use your 3 day programming knowledge to make something happen. Your friends don’t seem to care too much but it doesn’t even matter, you’re satisfied after you managed to get a language you barely know working with an API you’ve never used before. Wanting to do even more exciting things, you continue to write code but constantly hit road blocks, you eventually decide to ask for help but the people end up telling you you suck and need to learn how to program… maybe you’re just bad at learning.&lt;/p&gt;&lt;p&gt;But you’ve found something you find fun! So you keep going and eventually writing code becomes so enjoyable that you no longer have urges to play games all day, or even at all. Your desire to keep writing discord bots forces you to look up a bunch of things you didn’t know, you end up learning about promises, how to use a database, you finally understand how websites work and even attempt making one yourself to add a game in it.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;https://xetera.dev/static/a6e1e9fadf936e3f5c5602601a623300/b17f8/end_my_misery.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:49.6%;position:relative;bottom:0;left:0;background-image:url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHuzMNBf//EABgQAAIDAAAAAAAAAAAAAAAAAAERACAh/9oACAEBAAEFAsMQVP/EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAFBABAAAAAAAAAAAAAAAAAAAAIP/aAAgBAQAGPwJf/8QAGhABAAIDAQAAAAAAAAAAAAAAAQAhEBExUf/aAAgBAQABPyHhYxJaMFcqbfcf/9oADAMBAAIAAwAAABAj7//EABYRAQEBAAAAAAAAAAAAAAAAABEBEP/aAAgBAwEBPxB0z//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EIP/xAAaEAEBAAMBAQAAAAAAAAAAAAABABEhQWGB/9oACAEBAAE/EMqDo0zJg7MAiReaswin7N//2Q==&apos;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source srcset=&quot;/static/a6e1e9fadf936e3f5c5602601a623300/490da/end_my_misery.webp 250w,/static/a6e1e9fadf936e3f5c5602601a623300/e333e/end_my_misery.webp 500w,/static/a6e1e9fadf936e3f5c5602601a623300/54609/end_my_misery.webp 1000w,/static/a6e1e9fadf936e3f5c5602601a623300/de0ca/end_my_misery.webp 1500w,/static/a6e1e9fadf936e3f5c5602601a623300/5c42a/end_my_misery.webp 1600w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/webp&quot;&gt;
          &lt;source srcset=&quot;/static/a6e1e9fadf936e3f5c5602601a623300/0479a/end_my_misery.jpg 250w,/static/a6e1e9fadf936e3f5c5602601a623300/41099/end_my_misery.jpg 500w,/static/a6e1e9fadf936e3f5c5602601a623300/a2510/end_my_misery.jpg 1000w,/static/a6e1e9fadf936e3f5c5602601a623300/c58a3/end_my_misery.jpg 1500w,/static/a6e1e9fadf936e3f5c5602601a623300/b17f8/end_my_misery.jpg 1600w&quot; sizes=&quot;(max-width: 1000px) 100vw, 1000px&quot; type=&quot;image/jpeg&quot;&gt;
          &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;https://xetera.dev/static/a6e1e9fadf936e3f5c5602601a623300/a2510/end_my_misery.jpg&quot; alt=&quot;block game screenshot&quot; title=&quot;block game screenshot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;&gt;
        &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;But it sucks and you’re not happy with it and you know nobody else would be either. As if making games isn’t hard enough, you’re frustrated that your hard-earned programming knowledge isn’t helping you make your websites look half-decent. You keep up the hard work but every new design is a disaster more terrifying than the last and you’re not making any progress, maybe you’re just bad at learning.&lt;/p&gt;&lt;p&gt;A year passes and despite having a bunch of projects under your belt you look back and see that almost all of them are unfinished and abandoned projects you either gave up on or got bored of but at least you’re getting the hang of things now and continue working on things that excite you like you’ve been doing since day 1. Eventually you get around to learning things like React, Angular, Vue, MongoDB, your curiousity for programming spreads beyond your initial goal of web development and you find yourself looking up the documentation for different popular languages like C++ or Java but also more obscure stuff like Haskell, Purescript or Elm just because the way it works blew your mind and no other reason.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-hs&quot;&gt;spongebobCase :: String -&amp;gt; String
spongebobCase = zipWith ($) (cycle [toLower, toUpper])
-- spongebobCase &quot;memes&quot; =&amp;gt; &quot;mEmEs&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Math, a thing you once swore to never touch unless your life depended on it, suddenly became more interesting because of something you didn’t even know qualifies as math. You even started to earn money doing something you love and all this time you’ve been begrudgingly attending school, skipping classes (even computer science classes) to continue working on your projects. You finally take a step back and look at the progress you’ve made, you feel as if you’re capable of doing so much more than you ever thought you could be, and you think about the time you felt like an idiot in highschool for not being able to keep up in classes. How you weren’t able to get anywhere with things your parents and teachers kept telling you were important and you realize maybe you’re not bad at learning, maybe they’re bad at teaching…&lt;/p&gt;&lt;p&gt;But it only takes one to tango.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item><item><title><![CDATA[🔎 Asking good questions]]></title><link>https://xetera.dev/asking-good-questions/</link><guid isPermaLink="false">https://xetera.dev/asking-good-questions/</guid><pubDate>Thu, 07 May 2020 00:00:00 GMT</pubDate><enclosure url="https://xetera.dev/asking-good-questions/thumbnail.png" length="0" type="image/png"/><content:encoded>&lt;html&gt;&lt;head&gt;&lt;style data-emotion=&quot;css-global 1vepugy&quot;&gt;:host,:root,[data-theme]{--chakra-ring-inset:var(--chakra-empty,/*!*/ /*!*/);--chakra-ring-offset-width:0px;--chakra-ring-offset-color:#fff;--chakra-ring-color:rgba(66, 153, 225, 0.6);--chakra-ring-offset-shadow:0 0 #0000;--chakra-ring-shadow:0 0 #0000;--chakra-space-x-reverse:0;--chakra-space-y-reverse:0;--chakra-colors-transparent:transparent;--chakra-colors-current:currentColor;--chakra-colors-black:#000000;--chakra-colors-white:#FFFFFF;--chakra-colors-whiteAlpha-50:rgba(255, 255, 255, 0.04);--chakra-colors-whiteAlpha-100:rgba(255, 255, 255, 0.06);--chakra-colors-whiteAlpha-200:rgba(255, 255, 255, 0.08);--chakra-colors-whiteAlpha-300:rgba(255, 255, 255, 0.16);--chakra-colors-whiteAlpha-400:rgba(255, 255, 255, 0.24);--chakra-colors-whiteAlpha-500:rgba(255, 255, 255, 0.36);--chakra-colors-whiteAlpha-600:rgba(255, 255, 255, 0.48);--chakra-colors-whiteAlpha-700:rgba(255, 255, 255, 0.64);--chakra-colors-whiteAlpha-800:rgba(255, 255, 255, 0.80);--chakra-colors-whiteAlpha-900:rgba(255, 255, 255, 0.92);--chakra-colors-blackAlpha-50:rgba(0, 0, 0, 0.04);--chakra-colors-blackAlpha-100:rgba(0, 0, 0, 0.06);--chakra-colors-blackAlpha-200:rgba(0, 0, 0, 0.08);--chakra-colors-blackAlpha-300:rgba(0, 0, 0, 0.16);--chakra-colors-blackAlpha-400:rgba(0, 0, 0, 0.24);--chakra-colors-blackAlpha-500:rgba(0, 0, 0, 0.36);--chakra-colors-blackAlpha-600:rgba(0, 0, 0, 0.48);--chakra-colors-blackAlpha-700:rgba(0, 0, 0, 0.64);--chakra-colors-blackAlpha-800:rgba(0, 0, 0, 0.80);--chakra-colors-blackAlpha-900:rgba(0, 0, 0, 0.92);--chakra-colors-gray-50:#F7FAFC;--chakra-colors-gray-100:#EDF2F7;--chakra-colors-gray-200:#E2E8F0;--chakra-colors-gray-300:#CBD5E0;--chakra-colors-gray-400:#A0AEC0;--chakra-colors-gray-500:#718096;--chakra-colors-gray-600:#4A5568;--chakra-colors-gray-700:#2D3748;--chakra-colors-gray-800:#1A202C;--chakra-colors-gray-900:#171923;--chakra-colors-red-50:#FFF5F5;--chakra-colors-red-100:#FED7D7;--chakra-colors-red-200:#FEB2B2;--chakra-colors-red-300:#FC8181;--chakra-colors-red-400:#F56565;--chakra-colors-red-500:#E53E3E;--chakra-colors-red-600:#C53030;--chakra-colors-red-700:#9B2C2C;--chakra-colors-red-800:#822727;--chakra-colors-red-900:#63171B;--chakra-colors-orange-50:#FFFAF0;--chakra-colors-orange-100:#FEEBC8;--chakra-colors-orange-200:#FBD38D;--chakra-colors-orange-300:#F6AD55;--chakra-colors-orange-400:#ED8936;--chakra-colors-orange-500:#DD6B20;--chakra-colors-orange-600:#C05621;--chakra-colors-orange-700:#9C4221;--chakra-colors-orange-800:#7B341E;--chakra-colors-orange-900:#652B19;--chakra-colors-yellow-50:#FFFFF0;--chakra-colors-yellow-100:#FEFCBF;--chakra-colors-yellow-200:#FAF089;--chakra-colors-yellow-300:#F6E05E;--chakra-colors-yellow-400:#ECC94B;--chakra-colors-yellow-500:#D69E2E;--chakra-colors-yellow-600:#B7791F;--chakra-colors-yellow-700:#975A16;--chakra-colors-yellow-800:#744210;--chakra-colors-yellow-900:#5F370E;--chakra-colors-green-50:#F0FFF4;--chakra-colors-green-100:#C6F6D5;--chakra-colors-green-200:#9AE6B4;--chakra-colors-green-300:#68D391;--chakra-colors-green-400:#48BB78;--chakra-colors-green-500:#38A169;--chakra-colors-green-600:#2F855A;--chakra-colors-green-700:#276749;--chakra-colors-green-800:#22543D;--chakra-colors-green-900:#1C4532;--chakra-colors-teal-50:#E6FFFA;--chakra-colors-teal-100:#B2F5EA;--chakra-colors-teal-200:#81E6D9;--chakra-colors-teal-300:#4FD1C5;--chakra-colors-teal-400:#38B2AC;--chakra-colors-teal-500:#319795;--chakra-colors-teal-600:#2C7A7B;--chakra-colors-teal-700:#285E61;--chakra-colors-teal-800:#234E52;--chakra-colors-teal-900:#1D4044;--chakra-colors-blue-50:#ebf8ff;--chakra-colors-blue-100:#bee3f8;--chakra-colors-blue-200:#90cdf4;--chakra-colors-blue-300:#63b3ed;--chakra-colors-blue-400:#4299e1;--chakra-colors-blue-500:#3182ce;--chakra-colors-blue-600:#2b6cb0;--chakra-colors-blue-700:#2c5282;--chakra-colors-blue-800:#2a4365;--chakra-colors-blue-900:#1A365D;--chakra-colors-cyan-50:#EDFDFD;--chakra-colors-cyan-100:#C4F1F9;--chakra-colors-cyan-200:#9DECF9;--chakra-colors-cyan-300:#76E4F7;--chakra-colors-cyan-400:#0BC5EA;--chakra-colors-cyan-500:#00B5D8;--chakra-colors-cyan-600:#00A3C4;--chakra-colors-cyan-700:#0987A0;--chakra-colors-cyan-800:#086F83;--chakra-colors-cyan-900:#065666;--chakra-colors-purple-50:#FAF5FF;--chakra-colors-purple-100:#E9D8FD;--chakra-colors-purple-200:#D6BCFA;--chakra-colors-purple-300:#B794F4;--chakra-colors-purple-400:#9F7AEA;--chakra-colors-purple-500:#805AD5;--chakra-colors-purple-600:#6B46C1;--chakra-colors-purple-700:#553C9A;--chakra-colors-purple-800:#44337A;--chakra-colors-purple-900:#322659;--chakra-colors-pink-50:#FFF5F7;--chakra-colors-pink-100:#FED7E2;--chakra-colors-pink-200:#FBB6CE;--chakra-colors-pink-300:#F687B3;--chakra-colors-pink-400:#ED64A6;--chakra-colors-pink-500:#D53F8C;--chakra-colors-pink-600:#B83280;--chakra-colors-pink-700:#97266D;--chakra-colors-pink-800:#702459;--chakra-colors-pink-900:#521B41;--chakra-colors-linkedin-50:#E8F4F9;--chakra-colors-linkedin-100:#CFEDFB;--chakra-colors-linkedin-200:#9BDAF3;--chakra-colors-linkedin-300:#68C7EC;--chakra-colors-linkedin-400:#34B3E4;--chakra-colors-linkedin-500:#00A0DC;--chakra-colors-linkedin-600:#008CC9;--chakra-colors-linkedin-700:#0077B5;--chakra-colors-linkedin-800:#005E93;--chakra-colors-linkedin-900:#004471;--chakra-colors-facebook-50:#E8F4F9;--chakra-colors-facebook-100:#D9DEE9;--chakra-colors-facebook-200:#B7C2DA;--chakra-colors-facebook-300:#6482C0;--chakra-colors-facebook-400:#4267B2;--chakra-colors-facebook-500:#385898;--chakra-colors-facebook-600:#314E89;--chakra-colors-facebook-700:#29487D;--chakra-colors-facebook-800:#223B67;--chakra-colors-facebook-900:#1E355B;--chakra-colors-messenger-50:#D0E6FF;--chakra-colors-messenger-100:#B9DAFF;--chakra-colors-messenger-200:#A2CDFF;--chakra-colors-messenger-300:#7AB8FF;--chakra-colors-messenger-400:#2E90FF;--chakra-colors-messenger-500:#0078FF;--chakra-colors-messenger-600:#0063D1;--chakra-colors-messenger-700:#0052AC;--chakra-colors-messenger-800:#003C7E;--chakra-colors-messenger-900:#002C5C;--chakra-colors-whatsapp-50:#dffeec;--chakra-colors-whatsapp-100:#b9f5d0;--chakra-colors-whatsapp-200:#90edb3;--chakra-colors-whatsapp-300:#65e495;--chakra-colors-whatsapp-400:#3cdd78;--chakra-colors-whatsapp-500:#22c35e;--chakra-colors-whatsapp-600:#179848;--chakra-colors-whatsapp-700:#0c6c33;--chakra-colors-whatsapp-800:#01421c;--chakra-colors-whatsapp-900:#001803;--chakra-colors-twitter-50:#E5F4FD;--chakra-colors-twitter-100:#C8E9FB;--chakra-colors-twitter-200:#A8DCFA;--chakra-colors-twitter-300:#83CDF7;--chakra-colors-twitter-400:#57BBF5;--chakra-colors-twitter-500:#1DA1F2;--chakra-colors-twitter-600:#1A94DA;--chakra-colors-twitter-700:#1681BF;--chakra-colors-twitter-800:#136B9E;--chakra-colors-twitter-900:#0D4D71;--chakra-colors-telegram-50:#E3F2F9;--chakra-colors-telegram-100:#C5E4F3;--chakra-colors-telegram-200:#A2D4EC;--chakra-colors-telegram-300:#7AC1E4;--chakra-colors-telegram-400:#47A9DA;--chakra-colors-telegram-500:#0088CC;--chakra-colors-telegram-600:#007AB8;--chakra-colors-telegram-700:#006BA1;--chakra-colors-telegram-800:#005885;--chakra-colors-telegram-900:#003F5E;--chakra-colors-text-100:#eee;--chakra-colors-text-200:#f5f5f5;--chakra-colors-text-300:#9eaab7;--chakra-colors-text-400:#718096;--chakra-colors-text-500:#718096;--chakra-colors-bg-100:#0f1117;--chakra-colors-bg-300:#181b2b;--chakra-colors-bg-500:#232735;--chakra-colors-bgPrimary:#141621;--chakra-colors-bgSecondary:#181b2b;--chakra-colors-bgTertiary:#232735;--chakra-colors-bgBrand:hsl(333deg 52% 14%);--chakra-colors-borderSubtle:#181c24;--chakra-colors-borderSubtlePrimary:#1f2231;--chakra-colors-barelyVisible:#1f222a3d;--chakra-colors-brand-20:hsl(333deg, 100%, 45%);--chakra-colors-brand-80:hsl(333deg, 100%, 45%);--chakra-colors-brand-100:hsl(333deg, 100%, 45%);--chakra-colors-brandSecondary:#61b3cc;--chakra-colors-discord:awd;--chakra-colors-brandLight:hsl(333deg, 100%, 55%);--chakra-colors-bgPostHeader:#181b2b;--chakra-colors-bgPopupShadow:linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px,rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.4) 70% 20px, rgba(0, 0, 0, 0.7));--chakra-colors-discordBackground:#181b2b;--chakra-colors-bookBackground:rgb(0 0 0 / 0.2);--chakra-colors-discordTextColor:#dcddde;--chakra-colors-highlight:hsl(333deg, 100%, 45%);--chakra-borders-none:0;--chakra-borders-1px:1px solid;--chakra-borders-2px:2px solid;--chakra-borders-4px:4px solid;--chakra-borders-8px:8px solid;--chakra-fonts-heading:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-body:&apos;Wotfard&apos;,-apple-system,&apos;Segoe UI&apos;,&apos;Roboto&apos;,&apos;Ubuntu&apos;,&apos;Cantarell&apos;,&apos;Noto Sans&apos;,sans-serif,&apos;BlinkMacSystemFont&apos;,&apos;Helvetica Neue&apos;,&apos;Arial&apos;,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--chakra-fonts-mono:SFMono-Regular,Menlo,Monaco,Consolas,&quot;Liberation Mono&quot;,&quot;Courier New&quot;,monospace;--chakra-fontSizes-3xs:0.45rem;--chakra-fontSizes-2xs:0.625rem;--chakra-fontSizes-xs:13px;--chakra-fontSizes-sm:14px;--chakra-fontSizes-md:18px;--chakra-fontSizes-lg:22px;--chakra-fontSizes-xl:24px;--chakra-fontSizes-2xl:32px;--chakra-fontSizes-3xl:38px;--chakra-fontSizes-4xl:48px;--chakra-fontSizes-5xl:56px;--chakra-fontSizes-6xl:3.75rem;--chakra-fontSizes-7xl:4.5rem;--chakra-fontSizes-8xl:6rem;--chakra-fontSizes-9xl:8rem;--chakra-fontSizes-2md:20px;--chakra-fontWeights-hairline:100;--chakra-fontWeights-thin:200;--chakra-fontWeights-light:300;--chakra-fontWeights-normal:400;--chakra-fontWeights-medium:500;--chakra-fontWeights-semibold:600;--chakra-fontWeights-bold:700;--chakra-fontWeights-extrabold:800;--chakra-fontWeights-black:900;--chakra-letterSpacings-tighter:-0.05em;--chakra-letterSpacings-tight:-0.025em;--chakra-letterSpacings-normal:0;--chakra-letterSpacings-wide:0.025em;--chakra-letterSpacings-wider:0.05em;--chakra-letterSpacings-widest:0.1em;--chakra-lineHeights-3:.75rem;--chakra-lineHeights-4:1rem;--chakra-lineHeights-5:1.25rem;--chakra-lineHeights-6:1.5rem;--chakra-lineHeights-7:1.75rem;--chakra-lineHeights-8:2rem;--chakra-lineHeights-9:2.25rem;--chakra-lineHeights-10:2.5rem;--chakra-lineHeights-normal:normal;--chakra-lineHeights-none:1;--chakra-lineHeights-shorter:1.25;--chakra-lineHeights-short:1.375;--chakra-lineHeights-base:1.5;--chakra-lineHeights-tall:1.625;--chakra-lineHeights-taller:2;--chakra-radii-none:0;--chakra-radii-sm:0.125rem;--chakra-radii-base:0.25rem;--chakra-radii-md:0.375rem;--chakra-radii-lg:0.5rem;--chakra-radii-xl:0.75rem;--chakra-radii-2xl:1rem;--chakra-radii-3xl:1.5rem;--chakra-radii-full:9999px;--chakra-space-1:0.25rem;--chakra-space-2:0.5rem;--chakra-space-3:0.75rem;--chakra-space-4:1rem;--chakra-space-5:1.25rem;--chakra-space-6:1.5rem;--chakra-space-7:1.75rem;--chakra-space-8:2rem;--chakra-space-9:2.25rem;--chakra-space-10:2.5rem;--chakra-space-12:3rem;--chakra-space-14:3.5rem;--chakra-space-16:4rem;--chakra-space-20:5rem;--chakra-space-24:6rem;--chakra-space-28:7rem;--chakra-space-32:8rem;--chakra-space-36:9rem;--chakra-space-40:10rem;--chakra-space-44:11rem;--chakra-space-48:12rem;--chakra-space-52:13rem;--chakra-space-56:14rem;--chakra-space-60:15rem;--chakra-space-64:16rem;--chakra-space-72:18rem;--chakra-space-80:20rem;--chakra-space-96:24rem;--chakra-space-px:1px;--chakra-space-0-5:0.125rem;--chakra-space-1-5:0.375rem;--chakra-space-2-5:0.625rem;--chakra-space-3-5:0.875rem;--chakra-shadows-xs:0 0 0 1px rgba(0, 0, 0, 0.05);--chakra-shadows-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--chakra-shadows-base:0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);--chakra-shadows-md:0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06);--chakra-shadows-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1),0 4px 6px -2px rgba(0, 0, 0, 0.05);--chakra-shadows-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1),0 10px 10px -5px rgba(0, 0, 0, 0.04);--chakra-shadows-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--chakra-shadows-outline:0 0 0 3px rgba(66, 153, 225, 0.6);--chakra-shadows-inner:inset 0 2px 4px 0 rgba(0,0,0,0.06);--chakra-shadows-none:none;--chakra-shadows-dark-lg:rgba(0, 0, 0, 0.1) 0px 0px 0px 1px,rgba(0, 0, 0, 0.2) 0px 5px 10px,rgba(0, 0, 0, 0.4) 0px 15px 40px;--chakra-sizes-1:0.25rem;--chakra-sizes-2:0.5rem;--chakra-sizes-3:0.75rem;--chakra-sizes-4:1rem;--chakra-sizes-5:1.25rem;--chakra-sizes-6:1.5rem;--chakra-sizes-7:1.75rem;--chakra-sizes-8:2rem;--chakra-sizes-9:2.25rem;--chakra-sizes-10:2.5rem;--chakra-sizes-12:3rem;--chakra-sizes-14:3.5rem;--chakra-sizes-16:4rem;--chakra-sizes-20:5rem;--chakra-sizes-24:6rem;--chakra-sizes-28:7rem;--chakra-sizes-32:8rem;--chakra-sizes-36:9rem;--chakra-sizes-40:10rem;--chakra-sizes-44:11rem;--chakra-sizes-48:12rem;--chakra-sizes-52:13rem;--chakra-sizes-56:14rem;--chakra-sizes-60:15rem;--chakra-sizes-64:16rem;--chakra-sizes-72:18rem;--chakra-sizes-80:20rem;--chakra-sizes-96:24rem;--chakra-sizes-px:1px;--chakra-sizes-0-5:0.125rem;--chakra-sizes-1-5:0.375rem;--chakra-sizes-2-5:0.625rem;--chakra-sizes-3-5:0.875rem;--chakra-sizes-max:max-content;--chakra-sizes-min:min-content;--chakra-sizes-full:100%;--chakra-sizes-3xs:14rem;--chakra-sizes-2xs:16rem;--chakra-sizes-xs:20rem;--chakra-sizes-sm:24rem;--chakra-sizes-md:28rem;--chakra-sizes-lg:32rem;--chakra-sizes-xl:36rem;--chakra-sizes-2xl:42rem;--chakra-sizes-3xl:48rem;--chakra-sizes-4xl:56rem;--chakra-sizes-5xl:64rem;--chakra-sizes-6xl:72rem;--chakra-sizes-7xl:80rem;--chakra-sizes-8xl:90rem;--chakra-sizes-prose:60ch;--chakra-sizes-container-sm:640px;--chakra-sizes-container-md:768px;--chakra-sizes-container-lg:1024px;--chakra-sizes-container-xl:1280px;--chakra-zIndices-hide:-1;--chakra-zIndices-auto:auto;--chakra-zIndices-base:0;--chakra-zIndices-docked:10;--chakra-zIndices-dropdown:1000;--chakra-zIndices-sticky:1100;--chakra-zIndices-banner:1200;--chakra-zIndices-overlay:1300;--chakra-zIndices-modal:1400;--chakra-zIndices-popover:1500;--chakra-zIndices-skipLink:1600;--chakra-zIndices-toast:1700;--chakra-zIndices-tooltip:1800;--chakra-transition-property-common:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;--chakra-transition-property-colors:background-color,border-color,color,fill,stroke;--chakra-transition-property-dimensions:width,height;--chakra-transition-property-position:left,right,top,bottom;--chakra-transition-property-background:background-color,background-image,background-position;--chakra-transition-easing-ease-in:cubic-bezier(0.4, 0, 1, 1);--chakra-transition-easing-ease-out:cubic-bezier(0, 0, 0.2, 1);--chakra-transition-easing-ease-in-out:cubic-bezier(0.4, 0, 0.2, 1);--chakra-transition-duration-ultra-fast:50ms;--chakra-transition-duration-faster:100ms;--chakra-transition-duration-fast:150ms;--chakra-transition-duration-normal:200ms;--chakra-transition-duration-slow:300ms;--chakra-transition-duration-slower:400ms;--chakra-transition-duration-ultra-slow:500ms;--chakra-blur-none:0;--chakra-blur-sm:4px;--chakra-blur-base:8px;--chakra-blur-md:12px;--chakra-blur-lg:16px;--chakra-blur-xl:24px;--chakra-blur-2xl:40px;--chakra-blur-3xl:64px;}.chakra-ui-light :host:not([data-theme]),.chakra-ui-light :root:not([data-theme]),.chakra-ui-light [data-theme]:not([data-theme]),[data-theme=light] :host:not([data-theme]),[data-theme=light] :root:not([data-theme]),[data-theme=light] [data-theme]:not([data-theme]),:host[data-theme=light],:root[data-theme=light],[data-theme][data-theme=light]{--chakra-colors-chakra-body-text:var(--chakra-colors-gray-800);--chakra-colors-chakra-body-bg:var(--chakra-colors-white);--chakra-colors-chakra-border-color:var(--chakra-colors-gray-200);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-100);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-gray-500);}.chakra-ui-dark :host:not([data-theme]),.chakra-ui-dark :root:not([data-theme]),.chakra-ui-dark [data-theme]:not([data-theme]),[data-theme=dark] :host:not([data-theme]),[data-theme=dark] :root:not([data-theme]),[data-theme=dark] [data-theme]:not([data-theme]),:host[data-theme=dark],:root[data-theme=dark],[data-theme][data-theme=dark]{--chakra-colors-chakra-body-text:var(--chakra-colors-whiteAlpha-900);--chakra-colors-chakra-body-bg:var(--chakra-colors-gray-800);--chakra-colors-chakra-border-color:var(--chakra-colors-whiteAlpha-300);--chakra-colors-chakra-subtle-bg:var(--chakra-colors-gray-700);--chakra-colors-chakra-placeholder-color:var(--chakra-colors-whiteAlpha-400);}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 3kbdol&quot;&gt;html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;touch-action:manipulation;}body{position:relative;min-height:100%;font-feature-settings:&apos;kern&apos;;}*,*::before,*::after{border-width:0;border-style:solid;box-sizing:border-box;}main{display:block;}hr{border-top-width:1px;box-sizing:content-box;height:0;overflow:visible;}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em;}a{background-color:transparent;color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit;}abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}b,strong{font-weight:bold;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sub{bottom:-0.25em;}sup{top:-0.5em;}img{border-style:none;}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}button,input{overflow:visible;}button,select{text-transform:none;}button::-moz-focus-inner,[type=&quot;button&quot;]::-moz-focus-inner,[type=&quot;reset&quot;]::-moz-focus-inner,[type=&quot;submit&quot;]::-moz-focus-inner{border-style:none;padding:0;}fieldset{padding:0.35em 0.75em 0.625em;}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}progress{vertical-align:baseline;}textarea{overflow:auto;}[type=&quot;checkbox&quot;],[type=&quot;radio&quot;]{box-sizing:border-box;padding:0;}[type=&quot;number&quot;]::-webkit-inner-spin-button,[type=&quot;number&quot;]::-webkit-outer-spin-button{-webkit-appearance:none!important;}input[type=&quot;number&quot;]{-moz-appearance:textfield;}[type=&quot;search&quot;]{-webkit-appearance:textfield;outline-offset:-2px;}[type=&quot;search&quot;]::-webkit-search-decoration{-webkit-appearance:none!important;}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}details{display:block;}summary{display:-webkit-box;display:-webkit-list-item;display:-ms-list-itembox;display:list-item;}template{display:none;}[hidden]{display:none!important;}body,blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0;}button{background:transparent;padding:0;}fieldset{margin:0;padding:0;}ol,ul{margin:0;padding:0;}textarea{resize:vertical;}button,[role=&quot;button&quot;]{cursor:pointer;}button::-moz-focus-inner{border:0!important;}table{border-collapse:collapse;}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit;}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit;}img,svg,video,canvas,audio,iframe,embed,object{display:block;}img,video{max-width:100%;height:auto;}[data-js-focus-visible] :focus:not([data-focus-visible-added]):not([data-focus-visible-disabled]){outline:none;box-shadow:none;}select::-ms-expand{display:none;}:root{--chakra-vh:100vh;}@supports (height: -webkit-fill-available){:root{--chakra-vh:-webkit-fill-available;}}@supports (height: -moz-fill-available){:root{--chakra-vh:-moz-fill-available;}}@supports (height: 100dvh){:root{--chakra-vh:100dvh;}}&lt;/style&gt;&lt;style data-emotion=&quot;css-global e3coo2&quot;&gt;body{font-family:var(--chakra-fonts-body);color:#9eaab7;background:#0f1117;transition-property:background-color;transition-duration:var(--chakra-transition-duration-normal);line-height:var(--chakra-lineHeights-base);line-break:auto;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}*::-webkit-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::-moz-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*:-ms-input-placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*::placeholder{color:var(--chakra-colors-chakra-placeholder-color);}*,*::before,::after{border-color:var(--chakra-colors-chakra-border-color);word-wrap:break-word;}:root{-webkit-print-color-scheme:dark;color-scheme:dark;}ul{list-style-position:inside;}code{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;font-weight:var(--chakra-fontWeights-bold);font-size:0.85em;background:#2b141d;padding:0 6px;line-height:1.7;color:hsl(333deg, 100%, 45%);border-radius:5px;}.highlight-line{background:#181b2b;}.themed-scrollable::-webkit-scrollbar{width:8px;}.themed-scrollable::-webkit-scrollbar-track{width:8px;}*::-webkit-scrollbar-thumb{background:#232735;}.centered-grid&gt;*{grid-column:2/auto;}.blog-post :is(h1, h2, h3, h4, h5, h6)&gt;a{color:inherit;}.blog-post&gt;*{font-size:18px;}a{word-break:break-word;}.widebanner&gt;p{margin-bottom:0px;}.token-line{-webkit-padding-start:var(--chakra-space-3);padding-inline-start:var(--chakra-space-3);-webkit-padding-end:var(--chakra-space-3);padding-inline-end:var(--chakra-space-3);white-space:pre-wrap;word-break:break-word;}pre,kbd,samp{font-family:&apos;Jetbrains Mono&apos;,ui-monospace,Menlo,Monaco,&quot;Cascadia Mono&quot;,&quot;Segoe UI Mono&quot;,&quot;Roboto Mono&quot;,&quot;Oxygen Mono&quot;,&quot;Ubuntu Monospace&quot;,&quot;Source Code Pro&quot;,&quot;Fira Mono&quot;,&quot;Droid Sans Mono&quot;,&quot;Courier New&quot;,monospace;}.blog-post blockquote::before,.blog-post blockquote::after{width:3rem;display:block;border-top:1px solid #718096;opacity:0.4;content:&quot;&quot;;margin:0 auto;}.blog-post blockquote&gt;p{margin:3rem 0;font-weight:var(--chakra-fontWeights-medium);font-size:inherit;}::selection{background-color:#1f242e;}&lt;/style&gt;&lt;style data-emotion=&quot;css-global 1r1r0pm&quot;&gt;.js-focus-visible :focus:not([data-focus-visible-added]){outline:none;box-shadow:none;}&lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=&quot;headroom-wrapper&quot;&gt;&lt;div style=&quot;position:relative;top:0;left:0;right:0;z-index:1;-webkit-transform:translate3D(0, 0, 0);-ms-transform:translate3D(0, 0, 0);transform:translate3D(0, 0, 0)&quot; class=&quot;headroom headroom--unfixed&quot;&gt;&lt;style data-emotion=&quot;css hhbtuo&quot;&gt;.css-hhbtuo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;width:100%;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;padding:var(--chakra-space-3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);z-index:100;}@media screen and (min-width: 80em){.css-hhbtuo{-webkit-backdrop-filter:none;backdrop-filter:none;}}&lt;/style&gt;&lt;nav class=&quot;css-hhbtuo&quot;&gt;&lt;style data-emotion=&quot;css geek62&quot;&gt;.css-geek62{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}&lt;/style&gt;&lt;div class=&quot;css-geek62&quot;&gt;&lt;a aria-current=&quot;page&quot; aria-label=&quot;Go back home&quot; class=&quot;&quot; href=&quot;https://xetera.dev/&quot;&gt;&lt;style data-emotion=&quot;css in0rnb&quot;&gt;.css-in0rnb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;pointer-events:all;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}&lt;/style&gt;&lt;div class=&quot;css-in0rnb&quot;&gt;&lt;style data-emotion=&quot;css fubreh&quot;&gt;.css-fubreh{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:30px;height:30px;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}@media screen and (min-width: 30em){.css-fubreh{width:32px;height:32px;}}@media screen and (min-width: 48em){.css-fubreh{width:50px;height:50px;}}&lt;/style&gt;&lt;div class=&quot;css-fubreh&quot;&gt;&lt;style data-emotion=&quot;css xt6jsw animation-14pkoxc&quot;&gt;.css-xt6jsw{--skeleton-start-color:var(--chakra-colors-gray-100);--skeleton-end-color:var(--chakra-colors-gray-400);background:var(--skeleton-start-color);border-color:var(--skeleton-end-color);opacity:0.7;-webkit-animation:0.8s linear infinite alternate animation-14pkoxc;animation:0.8s linear infinite alternate animation-14pkoxc;box-shadow:var(--chakra-shadows-none);-webkit-background-clip:padding-box;background-clip:padding-box;cursor:default;color:var(--chakra-colors-transparent);pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:var(--chakra-radii-full);width:var(--chakra-sizes-full);height:var(--chakra-sizes-full);}.chakra-ui-dark .css-xt6jsw:not([data-theme]),[data-theme=dark] .css-xt6jsw:not([data-theme]),.css-xt6jsw[data-theme=dark]{--skeleton-start-color:var(--chakra-colors-gray-800);--skeleton-end-color:var(--chakra-colors-gray-600);}.css-xt6jsw::before,.css-xt6jsw::after,.css-xt6jsw *{visibility:hidden;}@-webkit-keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}@keyframes animation-14pkoxc{from{border-color:var(--skeleton-start-color);background:var(--skeleton-start-color);}to{border-color:var(--skeleton-end-color);background:var(--skeleton-end-color);}}&lt;/style&gt;&lt;div class=&quot;chakra-skeleton css-xt6jsw&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;style data-emotion=&quot;css 1v4udro&quot;&gt;.css-1v4udro{padding:var(--chakra-space-2);color:var(--chakra-colors-text-100);cursor:pointer;pointer-events:all;}&lt;/style&gt;&lt;button aria-label=&quot;theme switch&quot; class=&quot;css-1v4udro&quot;&gt;&lt;svg stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; viewBox=&quot;0 0 24 24&quot; height=&quot;30&quot; width=&quot;30&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;g&gt;&lt;path fill=&quot;none&quot; d=&quot;M0 0h24v24H0z&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M8 12h2v2H4v-2h2a6 6 0 1 1 6 6v-2a4 4 0 1 0-4-4zm-2 8h9v2H6v-2zm-4-4h8v2H2v-2zm9-15h2v3h-2V1zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3z&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/nav&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Regardless of whether you’re a complete beginner or an experienced programmer, chances are you’ve had to ask questions before. The most common form of this is going on Google to look up an error message, something you’ve surely done by now. You’ve probably also noticed that there are some ways you can formulate your questions on search engines that will give you better results than others like searching for “add element list python” as opposed to “how do I add an element to a list in python” (although search engines have gotten really good at handling the latter one nowadays too). But in a lot of cases, just Googling the error doesn’t help us so we resort to asking a real person, and much like a search engine, there are ways to make your experience with this much more pleasant by changing the way you form your question.&lt;/p&gt;&lt;h2 id=&quot;whats-a-bad-question&quot;&gt;&lt;a href=&quot;https://xetera.dev/#whats-a-bad-question&quot;&gt;What’s a bad question&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Before we can understand how to start asking good questions, we have to go over what a bad one looks like so we can avoid it in the future. Bad questions are considered bad because they do not communicate the intended idea efficiently or clearly.&lt;/p&gt;&lt;p&gt;Truly bad questions lead to a lot of back and forth between the person who needs help and the helper, which often start to resemble a police interrogation where the asker tries to withhold as much information as possible (for some reason) and must be asked for details one by one instead of providing it themselves.&lt;/p&gt;&lt;h3 id=&quot;examples-of-bad-questions&quot;&gt;&lt;a href=&quot;https://xetera.dev/#examples-of-bad-questions&quot;&gt;Examples of bad questions&lt;/a&gt;&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;AmazingProgrammer:&lt;/strong&gt; Any javascript pros in chat?&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;FantasticProgrammer:&lt;/strong&gt; I’m making a bot and it gives some errors, anyone help?&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;IncredibleProgrammer:&lt;/strong&gt; I’m trying to send a message but it says &lt;code&gt;cannot read property &apos;send&apos; of undefined&lt;/code&gt;, help?&lt;/p&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;PhenomenalProgrammer:&lt;/strong&gt; This isn’t working.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot;&gt;async def brrr():
  pass

brrr(money_printer)
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;GreatProgrammer&lt;/strong&gt; How to install node.js in ubuntu?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Let’s go over what’s wrong with each one of these.&lt;/p&gt;&lt;h4 id=&quot;asking-to-ask&quot;&gt;&lt;a href=&quot;https://xetera.dev/#asking-to-ask&quot;&gt;Asking to ask&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Amazing programmer&lt;/strong&gt; has a question but they haven’t even started asking it. It’s the question before the question. This wastes your own time as well as the helpers time, &lt;a href=&quot;https://dontasktoask.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener external&quot;&gt;don’t ask to ask&lt;/a&gt;. If you just post your question in one go, by the time someone who can help you sees it their response won’t be “yes?”, it will probably be the solution to your problem.&lt;/p&gt;&lt;h4 id=&quot;no-detail&quot;&gt;&lt;a href=&quot;https://xetera.dev/#no-detail&quot;&gt;No detail&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;This usually comes from frustration but &lt;strong&gt;FantasticProgrammer&lt;/strong&gt; hasn’t provided even the &lt;em&gt;slightest&lt;/em&gt; bit of information about what the problem is. It’s impossible to help them without a followup question.&lt;/p&gt;&lt;h4 id=&quot;insufficient-detail&quot;&gt;&lt;a href=&quot;https://xetera.dev/#insufficient-detail&quot;&gt;Insufficient detail&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;IncredibleProgrammer&lt;/strong&gt; provides more information than the previous person and sometimes this will be such a common problem that someone will be able to tell them what the problem is with almost no context but that’s rarely the case and figuring out what the problem is from just this much information is difficult.&lt;/p&gt;&lt;h4 id=&quot;missing-context&quot;&gt;&lt;a href=&quot;https://xetera.dev/#missing-context&quot;&gt;Missing context&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;A code sample helps, but helpers who haven’t mastered mind reading need more context to be able to offer a solution to your problem. “It’s not working” isn’t enough context, make sure you’re specific about your problems and what your expected outcomes are unlike &lt;strong&gt;PhenomenalProgrammer&lt;/strong&gt;.&lt;/p&gt;&lt;h4 id=&quot;no-effort&quot;&gt;&lt;a href=&quot;https://xetera.dev/#no-effort&quot;&gt;No effort&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Keep in mind that people who are helping you are &lt;em&gt;people&lt;/em&gt; and not a search engine. “How to install node.js in ubuntu?” is a question that should be asked on Google and not towards real people. If you have problems with installing node.js after Googling, you should definitely include that in your question so it’s easier to know where you are at with the problem without needing to prompt you for more details. Help the people who want to help you.&lt;/p&gt;&lt;h2 id=&quot;whats-a-good-question&quot;&gt;&lt;a href=&quot;https://xetera.dev/#whats-a-good-question&quot;&gt;What’s a good question&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Here’s a mental checklist that I try to keep track of when asking for help.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Written in one single message&lt;/li&gt;&lt;li&gt;Has sources for things I’ve looked up&lt;/li&gt;&lt;li&gt;Error messages (if any)&lt;/li&gt;&lt;li&gt;What I expected to happen&lt;/li&gt;&lt;li&gt;What actually happened&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</content:encoded></item></channel></rss>