<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: FF</title>
    <description>The latest articles on DEV Community by FF (@easy28).</description>
    <link>https://dev.to/easy28</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4161477%2F8ff0391b-afab-4e0c-ad26-d39bc7443dc6.png</url>
      <title>DEV Community: FF</title>
      <link>https://dev.to/easy28</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/easy28"/>
    <language>en</language>
    <item>
      <title>Your AI-Generated SVG Won't Render: The Same 8 Defects Every Time</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Mon, 02 Nov 2026 00:45:19 +0000</pubDate>
      <link>https://dev.to/easy28/your-ai-generated-svg-wont-render-the-same-8-defects-every-time-5e66</link>
      <guid>https://dev.to/easy28/your-ai-generated-svg-wont-render-the-same-8-defects-every-time-5e66</guid>
      <description>&lt;p&gt;You asked a model for an SVG. The code &lt;em&gt;looks&lt;/em&gt; right — tags, paths, colors, all plausible. You paste it into a file, open it in a browser, and get... a blank rectangle. No error, no warning, nothing.&lt;/p&gt;

&lt;p&gt;If this happens to you regularly, it's not bad luck. SVG is XML, and XML is unforgiving in a way HTML never is. A browser reading HTML will patch over a missing quote or an unclosed tag and render what it can. A browser reading SVG does none of that: one syntax slip and the whole document is rejected — usually silently.&lt;/p&gt;

&lt;p&gt;Language models generate SVG the way they generate everything else: token by token, plausibly. They pattern-match on millions of &lt;em&gt;examples&lt;/em&gt; without running an XML validator or a geometry engine. So they fail on exactly the details a validator would have caught — and they fail in the same ways, over and over. Here are the eight defects behind almost every broken AI-generated SVG I've seen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 8 defects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Missing &lt;code&gt;xmlns&lt;/code&gt; attribute.&lt;/strong&gt; The #1 killer. Without &lt;code&gt;xmlns="http://www.w3.org/2000/svg"&lt;/code&gt; the browser treats the file as generic XML. It may render inline in an HTML page, then fail as a standalone file or inside an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag — which makes it look like a caching bug. Models forget it constantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Missing or invented &lt;code&gt;viewBox&lt;/code&gt;.&lt;/strong&gt; No &lt;code&gt;viewBox&lt;/code&gt;, and the browser has no idea which part of the coordinate system to show. Or the model writes &lt;code&gt;viewBox="0 0 24 24"&lt;/code&gt; and then draws at &lt;code&gt;x="150"&lt;/code&gt; — every shape lands off-canvas and you get an empty frame.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Shapes translated out of view.&lt;/strong&gt; AI loves decorative &lt;code&gt;transform="translate(350, 280)"&lt;/code&gt; guesswork. The markup is valid, the preview is blank, and nothing tells you the artwork is sitting just outside the frame.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. A raw &lt;code&gt;&amp;amp;&lt;/code&gt; in a label.&lt;/strong&gt; SVG is strict XML. A label like &lt;code&gt;Tom &amp;amp; Jerry&lt;/code&gt; with a bare unescaped &lt;code&gt;&amp;amp;&lt;/code&gt; invalidates the &lt;em&gt;entire document&lt;/em&gt;. One character, whole file dead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. NaN and Infinity coordinates.&lt;/strong&gt; Models do arithmetic in public: &lt;code&gt;d="M 10 10 L NaN 50"&lt;/code&gt; or a radius of &lt;code&gt;Infinity&lt;/code&gt;. The path is syntactically present and renders as nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Unclosed or misnested tags.&lt;/strong&gt; Truncated output, a &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; that never closes, an attribute missing its quote. XML parsers are all-or-nothing — one structural slip and nothing renders at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Chat prose and code fences.&lt;/strong&gt; "Sure! Here's your logo:" ... &lt;code&gt;&lt;/code&gt;`&lt;code&gt;svg&lt;/code&gt; ... "Let me know if you'd like adjustments!" Paste that into a file and you have prose, fences, and markup layered together. Browsers don't strip any of it for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Everything &lt;code&gt;fill="none"&lt;/code&gt;.&lt;/strong&gt; The model styles each shape with &lt;code&gt;fill="none"&lt;/code&gt; and forgets to add a stroke. The file parses, the shapes exist, the image is empty. This one fools people the most because the SVG technically "works".&lt;/p&gt;

&lt;p&gt;Defects 1–6 kill the file outright at parse time. 7–8 are sneakier: the file &lt;em&gt;renders&lt;/em&gt;, it just renders empty — worse to debug because there's no error message to search for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-second diagnosis
&lt;/h2&gt;

&lt;p&gt;Before fixing anything, figure out which defect you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the file and search for &lt;code&gt;xmlns&lt;/code&gt;. Missing? That's defect 1.&lt;/li&gt;
&lt;li&gt;Check the &lt;code&gt;viewBox&lt;/code&gt; against the largest coordinates in the file. Drawing at 400 but viewing 0–24? Defect 2 or 3.&lt;/li&gt;
&lt;li&gt;Look for &lt;code&gt;NaN&lt;/code&gt;, &lt;code&gt;Infinity&lt;/code&gt;, or a bare &lt;code&gt;&amp;amp;&lt;/code&gt; outside entities. Defects 4 and 5.&lt;/li&gt;
&lt;li&gt;Text at the top of the file that isn't markup? Defect 7.&lt;/li&gt;
&lt;li&gt;Everything has &lt;code&gt;fill="none"&lt;/code&gt; and no &lt;code&gt;stroke&lt;/code&gt;? Defect 8.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or skip the manual pass: paste the raw chat output — prose and fences and all — into &lt;a href="https://svgeditor.dev/svg-repair" rel="noopener noreferrer"&gt;SVG Repair&lt;/a&gt;. It extracts the real markup, repairs the XML, adds the missing &lt;code&gt;xmlns&lt;/code&gt; and &lt;code&gt;viewBox&lt;/code&gt;, zeroes out NaN coordinates, expands the canvas to include off-screen shapes, makes invisible shapes visible, and shows you an itemized report of every defect next to a before/after preview. It actually renders the repaired file and checks it paints a non-empty image before claiming success. Everything runs client-side — the file never leaves your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prevent it at the source
&lt;/h2&gt;

&lt;p&gt;Repairing is faster than regenerating, but the cheapest fix is an SVG that isn't broken. Four lines added to the prompt eliminate most defects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Output only the raw SVG markup, no explanation, no code fences." — kills defect 7 entirely.&lt;/li&gt;
&lt;li&gt;"Include &lt;code&gt;xmlns&lt;/code&gt; and a &lt;code&gt;viewBox&lt;/code&gt; that matches the coordinate range you draw in." — kills defects 1 and 2.&lt;/li&gt;
&lt;li&gt;"Draw all shapes inside &lt;code&gt;0 0 512 512&lt;/code&gt;. Use no transforms." — kills defect 3.&lt;/li&gt;
&lt;li&gt;"No &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, no CSS classes, no text — convert text to paths." — kills the surprise below.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One more thing AI SVGs smuggle in: scripts
&lt;/h2&gt;

&lt;p&gt;Models occasionally emit &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags, &lt;code&gt;onload&lt;/code&gt; handlers, or &lt;code&gt;foreignObject&lt;/code&gt; blocks — sometimes because you asked for animation, sometimes out of nowhere. That matters beyond rendering: an SVG carrying scripts becomes a live XSS vector the moment someone opens it directly or inlines it into a page. If you're accepting SVGs from users, or embedding AI output into anything public, strip active content before it ships. The repair pipeline above strips it by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it renders again, keep going
&lt;/h2&gt;

&lt;p&gt;A repaired file is a working file, not a finished one. AI output carries redundant precision and empty groups that a proper &lt;a href="https://svgeditor.dev/svg-optimizer" rel="noopener noreferrer"&gt;SVG optimizer&lt;/a&gt; typically shaves 30–60%. Whole icon sets can be &lt;a href="https://svgeditor.dev/batch" rel="noopener noreferrer"&gt;repaired and converted in batch&lt;/a&gt;. And when the geometry is &lt;em&gt;almost&lt;/em&gt; right, a &lt;a href="https://svgeditor.dev/" rel="noopener noreferrer"&gt;free browser-based SVG editor&lt;/a&gt; lets you fix it visually — select and move shapes, edit text, adjust fills and strokes — without installing anything or uploading the file anywhere.&lt;/p&gt;

&lt;p&gt;The full write-up with more prompt examples is here: &lt;a href="https://svgeditor.dev/blog/ai-generated-svg-not-rendering" rel="noopener noreferrer"&gt;Why your AI-generated SVG doesn't render&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>The 2026 Favicon Checklist: every size your site actually needs</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Sun, 01 Nov 2026 10:36:52 +0000</pubDate>
      <link>https://dev.to/easy28/the-2026-favicon-checklist-every-size-your-site-actually-needs-31m3</link>
      <guid>https://dev.to/easy28/the-2026-favicon-checklist-every-size-your-site-actually-needs-31m3</guid>
      <description>&lt;p&gt;A few years ago "add a favicon" meant dropping one &lt;code&gt;favicon.ico&lt;/code&gt; in your site root. In 2026 that same site will look broken in at least four places: blurry in a retina browser tab, a generic globe in Google search results, a white square when an Android user saves it to their home screen, and a black blob on an iPhone.&lt;/p&gt;

&lt;p&gt;The fix isn't hard — but the requirements have quietly multiplied. Here's the complete size set that actually matters in 2026, why each one exists, and a copy-paste HTML block at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 favicon checklist
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Where it's used&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;16×16&lt;/td&gt;
&lt;td&gt;&lt;code&gt;favicon-16x16.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Classic browser tabs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;32×32&lt;/td&gt;
&lt;td&gt;&lt;code&gt;favicon-32x32.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retina tabs, Windows taskbar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;48×48&lt;/td&gt;
&lt;td&gt;inside &lt;code&gt;favicon.ico&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Windows site icons, older browsers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;180×180&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apple-touch-icon.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;iOS home screen, Safari pinned tabs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;192×192&lt;/td&gt;
&lt;td&gt;&lt;code&gt;android-chrome-192x192.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Android home screen, Chrome PWA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;512×512&lt;/td&gt;
&lt;td&gt;&lt;code&gt;android-chrome-512x512.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PWA splash screen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vector&lt;/td&gt;
&lt;td&gt;&lt;code&gt;favicon.svg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern browsers, dark-mode adaptive icons&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Six files. Not optional if you care about how your site presents on mobile and in search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why each size survives
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;16×16 + 32×32 — the browser tab.&lt;/strong&gt; 16×16 is the legacy default; 32×32 is what actually renders on high-DPI displays. Ship both. A tab icon that's only 16×16 gets smeared by the browser's upscaler on any modern laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;48×48 — inside the .ico.&lt;/strong&gt; The &lt;code&gt;.ico&lt;/code&gt; container can bundle multiple sizes in one file (16/32/48 is the common bundle), which is why a well-built &lt;code&gt;favicon.ico&lt;/code&gt; is still the most compatible single file you can ship. Windows site pins and plenty of crawlers read it first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;180×180 — Apple's tax.&lt;/strong&gt; iOS ignores your favicon entirely. When a user taps "Add to Home Screen", Safari reads exactly &lt;code&gt;apple-touch-icon.png&lt;/code&gt; at exactly 180×180. One more trap: iOS composites transparency onto black — export on your brand background or your logo gets a black box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;192×192 + 512×512 — Android &amp;amp; PWA.&lt;/strong&gt; These are read from &lt;code&gt;site.webmanifest&lt;/code&gt;. 192 is the Android home-screen icon; 512 powers the full-screen splash when your PWA launches. Ship a 512 source and downscale — never upscale, it shows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SVG — the modern bonus.&lt;/strong&gt; Every evergreen browser takes &lt;code&gt;favicon.svg&lt;/code&gt;, it scales everywhere, and it can embed a &lt;code&gt;prefers-color-scheme&lt;/code&gt; media query so your icon adapts to dark browser themes (worth its own post).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Google search angle people forget
&lt;/h2&gt;

&lt;p&gt;Google shows a favicon next to your result on mobile (and increasingly desktop). If your icon declaration is broken or too small, Google shows a generic globe — and search results with a real icon get measurably more clicks than the globe. Google recommends a square image ≥48×48, ideally multiples of 48, reachable at the root. This is one of the few branding fixes that directly affects CTR.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one source-of-truth rule
&lt;/h2&gt;

&lt;p&gt;Maintain &lt;strong&gt;one square master ≥512×512&lt;/strong&gt; (1024×1024 ideal) and derive everything from it. Hand-maintained icon folders are where stale sizes and 404s come from — treat favicon files as build output, not design artifacts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copy-paste block
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"48x48"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.svg"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/svg+xml"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon-16x16.png"&lt;/span&gt; &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"16x16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon-32x32.png"&lt;/span&gt; &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"32x32"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"apple-touch-icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/apple-touch-icon.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"manifest"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/site.webmanifest"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"theme-color"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"#ffffff"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The 30-second audit
&lt;/h2&gt;

&lt;p&gt;Not sure what your site currently serves? Two moves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check what's declared vs. what resolves&lt;/strong&gt; — the &lt;a href="https://favicon.one/favicon-checker/" rel="noopener noreferrer"&gt;Favicon Checker&lt;/a&gt; reads your live page and reports every icon it finds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate the full set from one image&lt;/strong&gt; — upload one square PNG to &lt;a href="https://favicon.one/" rel="noopener noreferrer"&gt;favicon.one&lt;/a&gt; and get a ZIP with every size above, the &lt;code&gt;.ico&lt;/code&gt;, the SVG, the manifest, and ready-to-paste HTML. Free, no signup, all in-browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you only have a JPG or an odd-size PNG, the &lt;a href="https://favicon.one/convert/png-to-ico/" rel="noopener noreferrer"&gt;PNG → ICO converter&lt;/a&gt; handles the legacy part.&lt;/p&gt;

&lt;p&gt;Complete reference with per-platform details: &lt;a href="https://favicon.one/blog/favicon-size-guide/" rel="noopener noreferrer"&gt;Favicon Size Guide: Every Dimension You Need in 2026&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I stopped pasting API responses into online JSON formatters — here's the 30-second audit I run instead</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Sun, 01 Nov 2026 01:44:28 +0000</pubDate>
      <link>https://dev.to/easy28/i-stopped-pasting-api-responses-into-online-json-formatters-heres-the-30-second-audit-i-run-2774</link>
      <guid>https://dev.to/easy28/i-stopped-pasting-api-responses-into-online-json-formatters-heres-the-30-second-audit-i-run-2774</guid>
      <description>&lt;p&gt;In November 2025, watchTowr Labs disclosed that CodeBeautify.org — one of the largest developer-tool sites on the internet — had been &lt;strong&gt;exposing user-pasted data through a public "Recent Links" feed&lt;/strong&gt;. Not a hypothetical: API keys, SSH private keys, and cloud credentials that developers pasted in to "just format this quickly" were reachable by anyone who knew where to look.&lt;/p&gt;

&lt;p&gt;If you've ever pasted a production payload into an online formatter, this one's for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The uncomfortable truth about "online tools"
&lt;/h2&gt;

&lt;p&gt;Most web-based formatters are not actually processing your data in your browser. Many POST your payload to a backend, format it server-side, and hand it back. Some store pastes to make "shareable links" — and shareable means enumerable.&lt;/p&gt;

&lt;p&gt;We put together a full technical breakdown of what happened, what was exposed, and the mechanics behind it:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://jsonformatter.app/news/codebeautify-data-leak-explained" rel="noopener noreferrer"&gt;The CodeBeautify data leak, explained&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-second audit (run this on any web tool)
&lt;/h2&gt;

&lt;p&gt;Before trusting any online tool with a real payload:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools → &lt;strong&gt;Network&lt;/strong&gt; tab, filter to Fetch/XHR&lt;/li&gt;
&lt;li&gt;Clear the log&lt;/li&gt;
&lt;li&gt;Paste your JSON and hit format&lt;/li&gt;
&lt;li&gt;Watch the network panel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Any request whose payload contains your data = it left your machine.&lt;/strong&gt; Doesn't matter what the landing page says about privacy. The network panel doesn't lie.&lt;/p&gt;

&lt;p&gt;Second check: load the page, turn off Wi-Fi (or use DevTools' offline throttling), and see if the tool still works. A genuinely client-side tool keeps working with zero connectivity. One that "phone home" dies on the spot.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real client-side pipeline looks like
&lt;/h2&gt;

&lt;p&gt;For the past year I've been using &lt;a href="https://jsonformatter.app" rel="noopener noreferrer"&gt;JSON Formatter App&lt;/a&gt; precisely because you can do this audit on it and come up clean — after the initial page load, everything runs in the browser: formatting, validation, transforms, the lot. No account, no cookies required, paste and go.&lt;/p&gt;

&lt;p&gt;The parts I actually use daily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validation that names the error.&lt;/strong&gt; Chrome 114+ changed how V8 reports JSON syntax errors, which silently broke a bunch of tools that parsed V8's error strings. A scanner written against the spec instead survives browser updates, and gives you plain-English errors with exact line/column plus jump-to-error: &lt;a href="https://jsonformatter.app/news/json-validator-error-locations" rel="noopener noreferrer"&gt;why JSON validators should name the error&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real jq in the browser.&lt;/strong&gt; Not a jq-&lt;em&gt;lookalike&lt;/em&gt; — actual jq compiled to WebAssembly: &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;sort_by&lt;/code&gt;, &lt;code&gt;group_by&lt;/code&gt;, object construction, with live preview as you type: &lt;a href="https://jsonformatter.app/news/json-transform-jq-jsonpath" rel="noopener noreferrer"&gt;jq + JSONPath transform panel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-click auto-repair&lt;/strong&gt; for the trailing-comma / single-quote / comment mistakes we all make when hand-editing config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you want the general checklist for evaluating whether a formatter is safe to use with sensitive payloads — the offline test, the network audit, what to look for in the privacy policy: &lt;strong&gt;&lt;a href="https://jsonformatter.app/news/secure-json-formatter-online" rel="noopener noreferrer"&gt;what makes a JSON formatter actually secure&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The habit worth keeping
&lt;/h2&gt;

&lt;p&gt;It's not "never use online tools" — it's &lt;strong&gt;know which tier of data you're pasting&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Never&lt;/strong&gt;: credentials, tokens, customer data, anything from prod → local tool or editor only&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gray zone&lt;/strong&gt;: internal payloads, staging responses → only tools that pass the network audit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fine&lt;/strong&gt;: public API samples, tutorial snippets, your kid's Minecraft JSON → whatever's fastest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CodeBeautify leak wasn't malice — it was a "shareable links" feature meeting real-world data. Every tool with a paste box and a server is one config change away from the same outcome. Audit before you paste, not after.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Full disclosure of the incident and what was exposed: &lt;a href="https://jsonformatter.app/news/codebeautify-data-leak-explained" rel="noopener noreferrer"&gt;CodeBeautify data leak explained&lt;/a&gt; — and yes, run the audit on our tool too. That's the point.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>privacy</category>
      <category>tutorial</category>
      <category>security</category>
    </item>
    <item>
      <title>Your internet isn't slow — it's bufferbloat. Diagnose it in 25 seconds.</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Sat, 31 Oct 2026 07:26:03 +0000</pubDate>
      <link>https://dev.to/easy28/your-internet-isnt-slow-its-bufferbloat-diagnose-it-in-25-seconds-b9a</link>
      <guid>https://dev.to/easy28/your-internet-isnt-slow-its-bufferbloat-diagnose-it-in-25-seconds-b9a</guid>
      <description>&lt;p&gt;You pay for 500 Mbps. At 2 a.m. everything is instant. At 7 p.m., when someone starts a game update, your video call turns into a slideshow — and the speed test you run right after still cheerfully reports 500 Mbps.&lt;/p&gt;

&lt;p&gt;Nothing is broken. Your speed test just doesn't measure the thing that's actually hurting you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number that speed tests don't show you
&lt;/h2&gt;

&lt;p&gt;Raw bandwidth answers "how much data can move per second". It says nothing about &lt;strong&gt;how long each tiny packet waits when the line is busy&lt;/strong&gt; — and that latency-under-load number is what real-time apps live and die by.&lt;/p&gt;

&lt;p&gt;That problem has a name: &lt;strong&gt;bufferbloat&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Modern routers and modems buffer packets instead of dropping them. That's polite under light load, but when a download saturates your link, outgoing packets — your video call frames, your game inputs — get stuck at the back of a huge queue. Your ping goes from 8 ms to 300+ ms while the download runs. The call stutters. The game desyncs. When the download finishes, everything is magically fine again, which is why it feels haunted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jitter&lt;/strong&gt; is the sibling problem: the &lt;em&gt;variation&lt;/em&gt; in your ping between packets. Real-time codecs can hide high latency better than they can hide inconsistent latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 25-second diagnosis
&lt;/h2&gt;

&lt;p&gt;You need a test that measures latency &lt;strong&gt;while the line is saturated&lt;/strong&gt;, not just at idle. Waveform's bufferbloat test is the well-known option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://speedpulse.tech" rel="noopener noreferrer"&gt;SpeedPulse&lt;/a&gt; is the one I built — free, no signup, no app, no cookies, everything runs client-side. One ~25-second run measures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Download / upload / idle ping&lt;/strong&gt; — the usual suspects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jitter&lt;/strong&gt; (RFC 3550-style mean difference between consecutive pings)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bufferbloat&lt;/strong&gt; — a ping train keeps running &lt;em&gt;during&lt;/em&gt; the download and upload phases; the tool reports &lt;code&gt;loaded latency − idle latency&lt;/code&gt; per direction and grades the worse one from A+ to F&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plain-English verdicts&lt;/strong&gt; for 4K streaming, gaming, video calls and browsing, so you don't have to interpret raw numbers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An 8-CDN cross-check&lt;/strong&gt; — after each test it pings 8 independent CDN edges (Cloudflare, jsDelivr, Fastly, GitHub, Google, AWS...). If the speed-test server is dramatically faster than the pack, your ISP may be prioritizing speed-test traffic — the classic reason "the test says I'm fine but everything feels slow"&lt;/li&gt;
&lt;li&gt;CSV export and a local history chart, all client-side&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reading the grade
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Grade&lt;/th&gt;
&lt;th&gt;Extra latency under load&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;&amp;lt; 5 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;&amp;lt; 30 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;&amp;lt; 60 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;&amp;lt; 200 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;&amp;lt; 400 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;≥ 400 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you score C or worse, you've found your problem.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Full disclosure: I built SpeedPulse. The grade scale is the same A+–F scheme Waveform and the bufferbloat.org community use, so results are comparable across tools — I'd rather share a standard than invent a flattering one.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The fixes that actually work
&lt;/h2&gt;

&lt;p&gt;In order of effectiveness:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable SQM with fq_codel/CAKE&lt;/strong&gt; on your router (trivial on OpenWrt; many stock firmwares ship a basic "QoS"). Smart queue management keeps buffers short so latency stays flat even at full load. This is &lt;em&gt;the&lt;/em&gt; fix — A+ grades come from this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cap your speeds ~5–10% below your ISP rate&lt;/strong&gt; in the SQM settings. Counter-intuitive but correct: queues then form inside your router, where SQM controls them, instead of inside the ISP's modem, where they don't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix the upload direction first.&lt;/strong&gt; Skinny upstreams bloat first — video calls die on &lt;em&gt;upload&lt;/em&gt; saturation (cloud backup + call = slideshow). If you can only cap one side, cap upload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go wired for the machine that matters.&lt;/strong&gt; Wi-Fi retransmissions and airtime contention add jitter no router setting can undo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check for speed-test favoritism.&lt;/strong&gt; If only the test's server is fast while every other CDN is slow, the 8-CDN panel makes the mismatch visible — worth raising with your ISP.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  For the nerds: how you measure this in a browser
&lt;/h2&gt;

&lt;p&gt;No ICMP, no raw sockets. A browser test times HTTPS round trips with &lt;code&gt;fetch(url, { mode: 'no-cors' })&lt;/code&gt; and &lt;code&gt;performance.now()&lt;/code&gt;. &lt;code&gt;no-cors&lt;/code&gt; returns an opaque response — no body, no status — but the full network round trip (DNS, TCP, TLS, HTTP) completes, which is all timing needs. Jitter is the mean absolute difference between consecutive samples; bufferbloat is the median loaded latency minus the idle median, measured per direction, graded on the worse of the two.&lt;/p&gt;

&lt;p&gt;Full methodology write-up, including the limitations we're honest about: &lt;a href="https://speedpulse.tech/blog/how-speedpulse-measures-jitter-and-bufferbloat/" rel="noopener noreferrer"&gt;How SpeedPulse measures jitter, bufferbloat and 8 CDN latencies&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Run the test on your line and drop your grade in the comments — happy to help interpret results: &lt;a href="https://speedpulse.tech" rel="noopener noreferrer"&gt;speedpulse.tech&lt;/a&gt;. Want the long-form bufferbloat explainer (router queue theory, CAKE vs fq_codel)? &lt;a href="https://speedpulse.tech/blog/what-is-bufferbloat/" rel="noopener noreferrer"&gt;What is bufferbloat?&lt;/a&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>tutorial</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Create Custom Emojis for Discord and Slack for Free (No Design Skills)</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Fri, 30 Oct 2026 17:44:31 +0000</pubDate>
      <link>https://dev.to/easy28/how-to-create-custom-emojis-for-discord-and-slack-for-free-no-design-skills-4efe</link>
      <guid>https://dev.to/easy28/how-to-create-custom-emojis-for-discord-and-slack-for-free-no-design-skills-4efe</guid>
      <description>&lt;p&gt;Every server admin and community manager hits the same wall eventually: you need a reaction emoji that simply doesn't exist. The inside joke lands, everyone types "we NEED that as an emoji," and then... nothing, because making custom emoji images sounds like a design job.&lt;/p&gt;

&lt;p&gt;It isn't. Here are two free ways to make original emojis in under a minute, plus how to upload them to Discord and Slack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1: Fuse two emojis into a new one
&lt;/h2&gt;

&lt;p&gt;The fastest route is an emoji "mixer" — it blends any two existing emojis into a brand-new one, no drawing required. &lt;a href="https://emojimagic.io/emoji-mixer" rel="noopener noreferrer"&gt;EmojiMagic.io's Emoji Mixer&lt;/a&gt; does this instantly in the browser:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick emoji A (say 🐱)&lt;/li&gt;
&lt;li&gt;Pick emoji B (say ☕)&lt;/li&gt;
&lt;li&gt;Get the fused result — cat + coffee usually lands somewhere adorable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every pair works, and you can regenerate until something clicks. No signup, no watermark, works on your phone too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2: Generate from a text prompt
&lt;/h2&gt;

&lt;p&gt;When you need something no two emojis can produce ("a capybara wearing a hard hat"), use an AI emoji generator instead. On &lt;a href="https://emojimagic.io" rel="noopener noreferrer"&gt;emojimagic.io&lt;/a&gt; you type the idea and get four styles back: Apple style, sticker, cute 3D, and flat. Free daily credits, no account needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Export a transparent PNG
&lt;/h2&gt;

&lt;p&gt;Both routes give you a &lt;strong&gt;transparent PNG&lt;/strong&gt; download — this matters, because a white box behind your emoji looks terrible on dark mode. The site handles transparency automatically; just hit download.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upload to Discord
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open your server → &lt;strong&gt;Server Settings → Emoji&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Upload Emoji&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Pick your PNG, give it a name in lowercase (e.g. &lt;code&gt;:catcoffee:&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Everyone in the server can now use it — including Nitro users, who can carry it to other servers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Discord resizes anything you throw at it, but square images around 128px look crispest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upload to Slack
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Workspace name → Customize workspace → Emoji&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add custom emoji&lt;/strong&gt;, name it, upload the PNG&lt;/li&gt;
&lt;li&gt;It's instantly available to the whole workspace&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Two quick tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test at small size.&lt;/strong&gt; Your emoji renders at 22px in most chat clients. If the detail disappears, simplify.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name for discoverability.&lt;/strong&gt; &lt;code&gt;:catcoffee:&lt;/code&gt; beats &lt;code&gt;:image3:&lt;/code&gt; — people type names to find reactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole workflow: mix or generate, download the transparent PNG, upload. The emoji your community asked for doesn't need a designer — just a free browser tab.&lt;/p&gt;

</description>
      <category>discord</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Emoji Semantic Search Works: Embeddings, Cosine Similarity, and 310k Vectors in Milliseconds</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Thu, 29 Oct 2026 16:56:52 +0000</pubDate>
      <link>https://dev.to/easy28/how-emoji-semantic-search-works-embeddings-cosine-similarity-and-310k-vectors-in-milliseconds-470d</link>
      <guid>https://dev.to/easy28/how-emoji-semantic-search-works-embeddings-cosine-similarity-and-310k-vectors-in-milliseconds-470d</guid>
      <description>&lt;p&gt;Type "cozy morning coffee" into our emoji search and it returns breakfast, warm-light and calm-mood emoji combinations — none of which share a single keyword with the query. No synonym table, no hand-tagging. That swap from keyword lookup to meaning-based matching is powered by the most boring-sounding stack in modern ML: text embeddings plus cosine similarity, scanned over ~310,000 precomputed vectors. This is the engineering tour of how it works and what we learned building it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keyword tables don't generalize
&lt;/h2&gt;

&lt;p&gt;Classic emoji search is a lookup table: "happy" maps to 😊, and if you type "joyful" you get nothing. Every synonym must be hand-tagged and every phrasing anticipated.&lt;/p&gt;

&lt;p&gt;Embedding-based search flips the problem. Instead of matching strings, you match points in a high-dimensional space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every query is converted into a vector of numbers.&lt;/li&gt;
&lt;li&gt;Every item in the catalog (for us, 310k+ emoji combinations) is also a vector, precomputed ahead of time.&lt;/li&gt;
&lt;li&gt;"Similar" simply means "geometrically close" — and geometry generalizes to words the system has never seen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The embedding pipeline, step by step
&lt;/h2&gt;

&lt;p&gt;We use an open-source multilingual model (BGE-M3, 1024 dimensions). Every text — queries at runtime, the whole catalog offline — goes through the same four stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Tokenization&lt;/strong&gt; — the model sees subword tokens, not words: &lt;code&gt;"cozy morning coffee" → ["co", "##zy", "morning", "coffee"]&lt;/code&gt;. Rare words split into known pieces, so the model can embed text it has never seen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transformer encoding&lt;/strong&gt; — each token flows through self-attention layers, exchanging information with every other token. "coffee" absorbs the fact that "morning" is next to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mean pooling&lt;/strong&gt; — one per-token vector each is averaged into a single 1024-dimension sentence vector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 normalization&lt;/strong&gt; — the vector is scaled to unit length, landing on the surface of a unit sphere.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last step is load-bearing. Once every vector has length 1, comparing &lt;em&gt;directions&lt;/em&gt; is all that's left.&lt;/p&gt;

&lt;h2&gt;
  
  
  The math that ranks everything
&lt;/h2&gt;

&lt;p&gt;Cosine similarity measures the angle between two vectors, ignoring length — from −1 (opposite) through 0 (unrelated) to +1 (same direction):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cos(θ) = (q · c) / (|q| × |c|)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because we normalized everything to unit length, the denominator is always 1 and the whole formula collapses to a plain &lt;strong&gt;dot product&lt;/strong&gt; — one multiply-and-add per dimension. There's also a neat identity that falls out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|q − c|² = 2 − 2 × cos(θ)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Smaller Euclidean distance and larger cosine similarity are the &lt;em&gt;same statement&lt;/em&gt; for unit vectors. Whether your nearest-neighbor code sorts by dot product, cosine, or Euclidean distance, the ranking is identical.&lt;/p&gt;

&lt;p&gt;Here's the entire mechanism in three dimensions, small enough to check by hand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;0.80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;   &lt;span class="c1"&gt;# "coffee"
&lt;/span&gt;&lt;span class="n"&gt;combos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.14&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;                &lt;span class="c1"&gt;# "hot drink"
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.93&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;                &lt;span class="c1"&gt;# "birthday party"
&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;cosine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;combos&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;combos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cosine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# [0.98 0.34]  -&amp;gt; hot drink wins by a mile
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scale that from 3 dimensions to 1024, and from 2 candidates to 310,000, and you have semantic emoji search.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lifecycle of one search
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Offline, once:&lt;/strong&gt; embed every catalog item and store its vector alongside its text. Vectors never change until the catalog does, so this cost is paid once — not per search.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Online, every search:&lt;/strong&gt; embed the query with the &lt;em&gt;same&lt;/em&gt; model, compute the dot product against the catalog, sort, return the top 100. Mixing models between index time and query time is the classic bug that quietly destroys result quality — two models produce two incompatible geometries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exact scan vs. ANN index
&lt;/h2&gt;

&lt;p&gt;1024 dimensions × 310k vectors is ~318 million multiply-adds per query. That sounds scary and isn't: a tight vectorized loop finishes in well under a second, and an exact scan returns the &lt;em&gt;provably&lt;/em&gt; best matches. Most systems switch to approximate nearest-neighbor (ANN) indexes — graph or cluster structures that trade a sliver of recall for an order-of-magnitude speedup — only past a few million vectors. Know your threshold before you reach for the fancy index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons we learned the hard way
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Normalize your vectors&lt;/strong&gt; at write time — cosine becomes a dot product and rankings stay consistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use one model everywhere.&lt;/strong&gt; Index and query vectors must share a geometry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precompute aggressively.&lt;/strong&gt; Only the live query should pay the embedding cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch p99, not the average.&lt;/strong&gt; Inference has cold starts; warm instances matter more than average speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate with real queries.&lt;/strong&gt; Cosine scores don't feel like relevance — the only test that counts is whether humans like what comes back.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want to see it ranking live, every query on &lt;a href="https://emojimagic.io/text-to-emoji" rel="noopener noreferrer"&gt;emojimagic.io/text-to-emoji&lt;/a&gt; runs exactly this pipeline — &lt;a href="https://emojimagic.io/blog/how-emoji-embeddings-work" rel="noopener noreferrer"&gt;this post on our blog&lt;/a&gt; has the full worked example, and the site itself is free with no signup if you'd rather throw queries at it than read about them.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>nlp</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why SVG Files from Figma Are 50–80% Dead Weight (and What to Strip Out)</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Tue, 27 Oct 2026 23:52:48 +0000</pubDate>
      <link>https://dev.to/easy28/why-svg-files-from-figma-are-50-80-dead-weight-and-what-to-strip-out-g3o</link>
      <guid>https://dev.to/easy28/why-svg-files-from-figma-are-50-80-dead-weight-and-what-to-strip-out-g3o</guid>
      <description>&lt;p&gt;Every project has at least one multi-kilobyte SVG icon that could have been a few hundred bytes. Design tools write SVG for &lt;em&gt;their&lt;/em&gt; convenience, not for the web — and the result is routinely 3–5× larger than it needs to be.&lt;/p&gt;

&lt;p&gt;Here are the 7 things making your SVGs bigger than they should be.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Editor metadata
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;metadata&amp;gt;&lt;/code&gt; blocks, &lt;code&gt;rdf:RDF&lt;/code&gt; payloads, generator comments — Figma, Illustrator and Inkscape all pad files with data only they read. Browsers never render it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Coordinate precision
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;74.98399992065430&lt;/code&gt; renders identically to &lt;code&gt;74.984&lt;/code&gt;. Dropping to 2–3 decimals is the single biggest win on path-heavy artwork — often half the file.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Empty and nested groups
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; wrappers that mirror the editor's layer panel but apply no transform or style.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Unused defs
&lt;/h2&gt;

&lt;p&gt;Gradients, filters, masks and symbols defined but never referenced by any shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Editor IDs and attributes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;id="Layer_1"&lt;/code&gt;, &lt;code&gt;data-name&lt;/code&gt;, &lt;code&gt;xmlns:serif&lt;/code&gt;, style attributes with no visual effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Whitespace
&lt;/h2&gt;

&lt;p&gt;Pretty-printed indentation and newlines — great for humans, dead weight for machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Embedded raster images (the trap)
&lt;/h2&gt;

&lt;p&gt;A base64 PNG hiding inside &lt;code&gt;&amp;lt;image&amp;gt;&lt;/code&gt; can be 95% of the file size, and &lt;strong&gt;no SVG optimizer can shrink it&lt;/strong&gt;. If your "SVG" is mostly an embedded bitmap, the honest fix is either re-exporting the artwork as true vectors or shipping an optimized WebP/JPEG instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much can you actually save?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Illustrator exports: &lt;strong&gt;50–80%&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Sketch: 40–70%&lt;/li&gt;
&lt;li&gt;Figma: 30–60%&lt;/li&gt;
&lt;li&gt;Hand-written SVGs: 5–15%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And an optimized SVG is plain text, so gzip/Brotli squeezes another 50–70% on the wire. The two stack — do both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate it
&lt;/h2&gt;

&lt;p&gt;If the same SVGs ship in an app, make optimization a compile step, exactly like minifying JavaScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vite:&lt;/strong&gt; vite-plugin-svgo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webpack:&lt;/strong&gt; svgo-loader&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any CI:&lt;/strong&gt; &lt;code&gt;npx svgo -f src/icons -o dist/icons&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep editable originals in the design repo, let the pipeline emit optimized files, and nobody has to remember anything again.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The full guide — with a browser-based optimizer (SVGO running client-side, no upload) and a batch processor for whole icon sets — is at &lt;a href="https://svgeditor.dev/svg-optimizer" rel="noopener noreferrer"&gt;svgeditor.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>svg</category>
      <category>webdev</category>
      <category>performance</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Favicon not showing? Here's how to fix it (10 causes)</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Tue, 27 Oct 2026 03:37:08 +0000</pubDate>
      <link>https://dev.to/easy28/favicon-not-showing-heres-how-to-fix-it-10-causes-ehb</link>
      <guid>https://dev.to/easy28/favicon-not-showing-heres-how-to-fix-it-10-causes-ehb</guid>
      <description>&lt;p&gt;A missing or broken favicon is one of the most common questions on Stack Overflow — and the answer is almost always one of ten things. Work through this checklist top to bottom and you'll find it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Browser caching (the #1 cause)
&lt;/h2&gt;

&lt;p&gt;Browsers cache favicons extremely aggressively — far more than regular pages. Even after you've fixed the issue, the old (broken) icon can persist for days. Test in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hard refresh:&lt;/strong&gt; Ctrl/Cmd + Shift + R&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incognito / private window&lt;/strong&gt; — if it shows there, it's just your cache&lt;/li&gt;
&lt;li&gt;Visit the file directly: open &lt;code&gt;https://yourdomain.com/favicon.ico&lt;/code&gt;. If you see the image, the file is fine and it's a cache/link issue.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Wrong file path
&lt;/h2&gt;

&lt;p&gt;The href in your &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; must point to where the file actually is. A leading slash (&lt;code&gt;/favicon.ico&lt;/code&gt;) means site root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ❌ wrong if file is in /assets/ --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"favicon.ico"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- ✅ absolute path from site root --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- ✅ or the real location --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/assets/favicon.ico"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Missing &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag
&lt;/h2&gt;

&lt;p&gt;Some browsers fall back to &lt;code&gt;/favicon.ico&lt;/code&gt; automatically, but you should never rely on that. Always declare icons explicitly in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/x-icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/png"&lt;/span&gt; &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"32x32"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon-32x32.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"apple-touch-icon"&lt;/span&gt; &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"180x180"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/apple-touch-icon.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Wrong MIME type
&lt;/h2&gt;

&lt;p&gt;If your server serves &lt;code&gt;.ico&lt;/code&gt; as &lt;code&gt;image/png&lt;/code&gt; (or vice versa) some browsers will refuse to render it. &lt;code&gt;.ico&lt;/code&gt; should be &lt;code&gt;image/x-icon&lt;/code&gt; or &lt;code&gt;image/vnd.microsoft.icon&lt;/code&gt;; PNG should be &lt;code&gt;image/png&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. File not deployed
&lt;/h2&gt;

&lt;p&gt;Check that the file actually made it to production. Open the file URL in a new tab. A 404 means it's not there — rebuild and redeploy, and confirm your build pipeline copies favicons into the output directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Non-square source image
&lt;/h2&gt;

&lt;p&gt;Favicons must be square. If your source image isn't 1:1, browsers may show a stretched or blank icon. Crop first.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Framework-specific gotchas
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Next.js App Router:&lt;/strong&gt; icon files go in &lt;code&gt;app/&lt;/code&gt; (not &lt;code&gt;public/&lt;/code&gt;) for auto-detection.&lt;br&gt;
&lt;strong&gt;Next.js Pages Router:&lt;/strong&gt; files go in &lt;code&gt;public/&lt;/code&gt;, tags go in &lt;code&gt;pages/_document.tsx&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Webpack / Vite:&lt;/strong&gt; make sure &lt;code&gt;favicon.ico&lt;/code&gt; is in your &lt;code&gt;public/&lt;/code&gt; or &lt;code&gt;static/&lt;/code&gt; directory and referenced in your HTML template.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. HTTPS / mixed content
&lt;/h2&gt;

&lt;p&gt;If your site is HTTPS but the favicon is referenced over HTTP, browsers will block it as mixed content. Always use HTTPS URLs or relative paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Service worker caching an old version
&lt;/h2&gt;

&lt;p&gt;If you have a PWA with a service worker, it may be serving a cached HTML that references an old favicon. Update and re-register the service worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. The SVG favicon isn't supported
&lt;/h2&gt;

&lt;p&gt;SVG favicons aren't supported in every browser (notably older Chrome on Android). Always provide a PNG/ICO fallback alongside an SVG.&lt;/p&gt;

&lt;h2&gt;
  
  
  Still stuck? Automate the diagnosis
&lt;/h2&gt;

&lt;p&gt;Paste your URL into the &lt;a href="https://favicon.one/favicon-checker" rel="noopener noreferrer"&gt;Favicon Checker&lt;/a&gt; and it will tell you exactly which icons and tags are missing or broken — no guessing.&lt;/p&gt;




&lt;p&gt;Need a clean favicon package to replace a broken one? &lt;a href="https://favicon.one/" rel="noopener noreferrer"&gt;Generate one free at Favicon.one&lt;/a&gt; — text, emoji, SVG or image, every size and format, all processed locally in your browser.&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>Making legacy regexes readable — without changing what they match</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Mon, 26 Oct 2026 19:08:05 +0000</pubDate>
      <link>https://dev.to/easy28/making-legacy-regexes-readable-without-changing-what-they-match-4l4l</link>
      <guid>https://dev.to/easy28/making-legacy-regexes-readable-without-changing-what-they-match-4l4l</guid>
      <description>&lt;p&gt;A pattern like this ships in real projects every day:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^(?\[(?:[A-Za-z0-9_.-]+)\])|^(?[A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[^#\n]*)\s*(?:#.*)?$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An INI-line parser: a section header or a key–value pair, three quoting modes for the value, trailing comments. Perfectly readable — to the person who wrote it, today. Come back in three months, or hand it to a teammate, and the review comment is always the same: &lt;em&gt;what does this actually match?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Formatting solves this the way it's solved for every other language. The same pattern, laid out by structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight augeas"&gt;&lt;code&gt;&lt;span class="err"&gt;^&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="kn"&gt;A&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kn"&gt;Za&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;z0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;9_&lt;/span&gt;&lt;span class="o"&gt;.-&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="err"&gt;^&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kn"&gt;A&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kn"&gt;Za&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;z_&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="kn"&gt;A&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kn"&gt;Za&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;z0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;9_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"
   (?: [^"&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;\\&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="s"&gt;"
| ' (?: [^'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt; . )* '
| [^#&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;]*
)
&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s"&gt;s* (?:&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s"&gt;#.*)?
$
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two branches instead of one buried &lt;code&gt;|&lt;/code&gt;; three quote styles you can point at; a comment-stripping tail that's obviously a tail. Same language — the difference is purely typographic, which is exactly the point.&lt;/p&gt;

&lt;p&gt;That's the Format panel in &lt;a href="https://regextester.dev" rel="noopener noreferrer"&gt;RegexTester.dev&lt;/a&gt;: open the toolbar's Format button or the deep link &lt;a href="https://regextester.dev/format" rel="noopener noreferrer"&gt;regextester.dev/format&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa8m9hq794dliwkfi81at.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa8m9hq794dliwkfi81at.webp" alt="Format toolbar" width="798" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Three modes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pretty&lt;/strong&gt; — free-spacing layout with indented groups and stacked alternation branches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvwc9lkfpwox10sxght0.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvwc9lkfpwox10sxght0.webp" alt="Pretty output" width="799" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Annotated&lt;/strong&gt; — the pretty layout plus AST-derived inline comments naming each construct as it appears (&lt;code&gt;alternation&lt;/code&gt;, &lt;code&gt;negative lookahead&lt;/code&gt;, &lt;code&gt;named capture&lt;/code&gt;, …).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbfwh2x0bwcm0tnlxkeor.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbfwh2x0bwcm0tnlxkeor.webp" alt="Annotated output" width="799" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minify&lt;/strong&gt; — the reverse direction: comments and free-spacing whitespace stripped back down to a single dense line for shipping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftkzl1pkd4f6o8sshlxob.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftkzl1pkd4f6o8sshlxob.webp" alt="Minify output" width="799" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the layout can't change behavior
&lt;/h2&gt;

&lt;p&gt;Whitespace only becomes syntax when the &lt;strong&gt;x / extended flag&lt;/strong&gt; is on, so the formatter emits its output &lt;em&gt;with the x flag enabled for your dialect&lt;/em&gt; — PCRE2, Python, Java and .NET all spell it slightly differently, and the panel handles that. What it must never do is insert whitespace inside a character class (where it would be literal), inside a quantifier, or escape sequences that carry meaning. The layout rule is simple: only touch whitespace and comments &lt;strong&gt;outside&lt;/strong&gt; classes and escapes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verified, not assumed
&lt;/h2&gt;

&lt;p&gt;"Trust me, the layout is safe" is not a review argument, so the panel shows its work at the bottom of every run:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Round-trip proof&lt;/strong&gt; — the formatter re-minifies its own output and compares it, byte for byte, with the escaped input. If the only difference is whitespace and comments outside classes — exactly what x mode ignores — you get a green &lt;em&gt;Round-trip exact&lt;/em&gt; line.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjygqcslifc3svaf24rdt.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjygqcslifc3svaf24rdt.webp" alt="Equivalence proof" width="735" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Live behavior check&lt;/strong&gt; — both forms (original, and formatted with x enabled) are executed against your current test string on the real engine for your flavor, and every match is compared: text, position, and each capture group's content. Only identical match lists earn the green &lt;em&gt;Behavior verified&lt;/em&gt; line.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If either check fails, the line turns red and points you at the parse errors above. Formatting a regex you can't test is guesswork; here it's a proof.&lt;/p&gt;




&lt;p&gt;Try it: open &lt;a href="https://regextester.dev/format" rel="noopener noreferrer"&gt;regextester.dev/format&lt;/a&gt;, paste your gnarliest pattern, and read it in one click — then let the round-trip proof tell you the formatter didn't change a thing.&lt;/p&gt;

&lt;p&gt;Full write-up: &lt;a href="https://regextester.dev/blog/regex-formatter" rel="noopener noreferrer"&gt;regextester.dev/blog/regex-formatter&lt;/a&gt;. Free, no signup, everything runs locally in your browser.&lt;/p&gt;

</description>
      <category>regex</category>
      <category>cleancode</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>One regex, seven engines: catch portability bugs before you ship</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Mon, 26 Oct 2026 18:46:32 +0000</pubDate>
      <link>https://dev.to/easy28/one-regex-seven-engines-catch-portability-bugs-before-you-ship-jgm</link>
      <guid>https://dev.to/easy28/one-regex-seven-engines-catch-portability-bugs-before-you-ship-jgm</guid>
      <description>&lt;p&gt;"Regular expressions" is not one language. It's a family of dialects that look almost identical and disagree in exactly the places you don't look until production breaks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;\w&lt;/code&gt; is Unicode-aware by default in Python 3, PCRE2 and .NET — but ASCII-only in JavaScript.&lt;/li&gt;
&lt;li&gt;Lookbehind must be fixed-width in PCRE2; .NET accepts variable width; RE2-based engines reject it entirely.&lt;/li&gt;
&lt;li&gt;Possessive quantifiers, atomic groups, &lt;code&gt;\K&lt;/code&gt;, named-group syntax &lt;code&gt;(?&amp;lt;name&amp;gt;…)&lt;/code&gt; vs &lt;code&gt;(?P&amp;lt;name&amp;gt;…)&lt;/code&gt; — every one of these is a line in some engine's grammar and an error (or a silent behavior change) in another's.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The standard workflow makes this invisible. You test the pattern in one tester with one flavor selected, it works, you paste it into another language — and the failure shows up far away from the regex: a log line that never matches, a validation that rejects valid input, an import script that silently skips rows.&lt;/p&gt;

&lt;p&gt;A flavor selector doesn't solve this either — you'd still have to try every flavor by hand and compare results from memory. What you need is every engine answering at once, side by side, on the same input. That's what the Compat button in &lt;a href="https://regextester.dev" rel="noopener noreferrer"&gt;RegexTester.dev&lt;/a&gt; does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seven engine paths, one click
&lt;/h2&gt;

&lt;p&gt;Type your pattern and a representative test string, then hit the Compat button in the toolbar — or open the deep link &lt;a href="https://regextester.dev/compat" rel="noopener noreferrer"&gt;regextester.dev/compat&lt;/a&gt; directly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqd10mogm08i9i0hrm0mq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqd10mogm08i9i0hrm0mq.webp" alt="Compat toolbar" width="795" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One pattern runs through seven execution paths in parallel:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;PCRE2&lt;/strong&gt; — real engine, compiled to WebAssembly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt; (&lt;code&gt;regexp&lt;/code&gt;) — real engine, WebAssembly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust&lt;/strong&gt; (&lt;code&gt;regex&lt;/code&gt;) — real engine, WebAssembly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript&lt;/strong&gt; — the browser's native RegExp&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.NET&lt;/strong&gt; — a real interpreter for &lt;code&gt;System.Text.RegularExpressions&lt;/code&gt; syntax&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt; — parser plus normalize-and-run path&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java&lt;/strong&gt; — parser plus normalize-and-run path&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not simulated: the WASM paths are the actual engine builds, so a rejection or a match here is what the real engine does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three ways a port fails
&lt;/h2&gt;

&lt;p&gt;Every engine reports one of three outcomes, and the panel clusters engines by their exact match sets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rejection&lt;/strong&gt; — the pattern doesn't even compile. RE2's rejection of lookbehind, or a possessive quantifier a dialect has never heard of, is a build error you want to know about &lt;em&gt;before&lt;/em&gt; the port.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo3kn9rfbmg1mjbk8qbtd.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo3kn9rfbmg1mjbk8qbtd.webp" alt="Rejection" width="800" height="797"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Silent divergence&lt;/strong&gt; — the worst one. The pattern compiles everywhere and simply disagrees. Classic example: &lt;code&gt;\w+&lt;/code&gt; against Unicode input gives JS and Java four matches where the other five engines give two, because &lt;code&gt;\w&lt;/code&gt; is ASCII-only there. No error, no warning — different data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsphfm9szwwrthqjpvqff.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsphfm9szwwrthqjpvqff.webp" alt="Divergence" width="800" height="749"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full agreement&lt;/strong&gt; — all seven engines return identical match sets (text, position, groups), and the panel says so explicitly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbkri52lg1t5wtpddwzy7.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbkri52lg1t5wtpddwzy7.webp" alt="Fully compatible" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Exporting the verdict
&lt;/h2&gt;

&lt;p&gt;The verdict copy is written to be pasted: one click copies a Markdown report listing every engine, its outcome, and the divergent match sets — drop it into a PR when you're porting a pattern between services written in different languages.&lt;/p&gt;




&lt;p&gt;Try it: open &lt;a href="https://regextester.dev/compat" rel="noopener noreferrer"&gt;regextester.dev/compat&lt;/a&gt;, paste the pattern you're about to port, and see all seven verdicts in a couple of seconds.&lt;/p&gt;

&lt;p&gt;Full write-up: &lt;a href="https://regextester.dev/blog/regex-compatibility-checker" rel="noopener noreferrer"&gt;regextester.dev/blog/regex-compatibility-checker&lt;/a&gt;. Free, no signup, everything runs locally in your browser.&lt;/p&gt;

</description>
      <category>regex</category>
      <category>portability</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Buying the dip without catching the knife: a 2-line crypto pullback rule, walk-forward validated across 40 coins</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Sun, 25 Oct 2026 14:38:27 +0000</pubDate>
      <link>https://dev.to/easy28/buying-the-dip-without-catching-the-knife-a-2-line-crypto-pullback-rule-walk-forward-validated-3g5p</link>
      <guid>https://dev.to/easy28/buying-the-dip-without-catching-the-knife-a-2-line-crypto-pullback-rule-walk-forward-validated-3g5p</guid>
      <description>&lt;p&gt;"Buy the dip" is the most repeated advice in crypto — and following it blindly is one of the most reliable ways to lose money. A 6% pullback inside a bull market and a 6% bleed on the way to zero print the same red candle. One is an opportunity; the other is a knife.&lt;/p&gt;

&lt;p&gt;We built &lt;strong&gt;Trend Dip&lt;/strong&gt;, a pullback strategy that only buys reclaims inside an uptrend, validated it walk-forward across 40 coins on 4-hour bars, and shipped it as a free preset in our in-browser backtester — no signup, the whole engine is WASM running locally in your browser, so you can re-run every number in this post on any coin in about a second.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule (two lines)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ENTRY:CROSS(C,LOWER) &amp;amp;&amp;amp; C&amp;gt;TRENDMA    // buy the reclaim of the lower Bollinger band, in an uptrend
EXIT:CROSS(C,MID)                    // sell at the mid band
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…where &lt;code&gt;LOWER = MA(C,20) − 2·STD(C,20)&lt;/code&gt;, &lt;code&gt;MID = MA(C,20)&lt;/code&gt;, and &lt;code&gt;TRENDMA = MA(C,100)&lt;/code&gt;. Each piece earns its place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C &amp;gt; MA100 — the trend filter.&lt;/strong&gt; This is what separates a dip from a knife. Below the 100-bar average, the same band reclaim is ignored entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CROSS(C, LOWER) — buy the reclaim, not the touch.&lt;/strong&gt; The entry fires on the bar whose &lt;em&gt;close comes back above&lt;/em&gt; the band. The market has already rejected the low once before you spend a cent. This single change moved the OOS win rate by roughly ten points versus buying the first touch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit at the mid band.&lt;/strong&gt; The thesis is snap-back to the 20-bar mean, so that's where the trade ends. We tried smarter exits — trailing lows, trend-break exits — every one performed &lt;em&gt;worse&lt;/em&gt; out of sample.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No stop in the formula.&lt;/strong&gt; Deliberate: 4h crypto charts routinely flush 5% below the band and revert by the next close, and a stop converts those wicks into realized losses. Adding a 10–20% protective stop changed the results almost imperceptibly (stops almost never fired). The backtester still gives you an optional stop field if you want a hard tail cap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo7wmlxt3wwpbfzwhxzdr.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo7wmlxt3wwpbfzwhxzdr.webp" alt="Trend Dip backtest page on BTC/USDT 4h — chart, formula, equity curve, stats grid and trade list" width="800" height="885"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How we validated it
&lt;/h2&gt;

&lt;p&gt;Four rules, all of which matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Not one chart — forty.&lt;/strong&gt; BTC, ETH, SOL, BNB, XRP, DOGE, AVAX, DOT and 32 more majors with long histories. A rule that only works on a cherry-picked chart is a screenshot, not an edge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Walk-forward, not full-history.&lt;/strong&gt; Each coin's ~500 days of 4h bars split 70/30: the first 70% is where parameters would effectively have been chosen; the final 30% is scored blind as one continuous out-of-sample segment. All headline numbers below are OOS only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realistic fills.&lt;/strong&gt; Signals confirm at bar close, fill at the &lt;em&gt;next&lt;/em&gt; bar's open — no lookahead — with 0.10% taker fee + 0.05% slippage per side (~0.3% round trip). The same engine and simulator that power the public backtest page ran every test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmarks.&lt;/strong&gt; The identical harness scored the nine other strategies on the site on the same data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Out-of-sample metric (40 coins, 4h, 70/30)&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;Win rate, all held-out trades&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;73.6%&lt;/strong&gt; (174 trades)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Win rate, in-sample (for contrast)&lt;/td&gt;
&lt;td&gt;62.9% (267 trades)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coins profitable OOS&lt;/td&gt;
&lt;td&gt;26 / 40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coins beating buy &amp;amp; hold OOS&lt;/td&gt;
&lt;td&gt;24 / 40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coins winning ≥50% of held-out trades&lt;/td&gt;
&lt;td&gt;33 / 35 with ≥3 trades&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median per-coin max drawdown&lt;/td&gt;
&lt;td&gt;−6.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worst / median / best held-out trade&lt;/td&gt;
&lt;td&gt;−16.7% / +1.2% / +34.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average holding time&lt;/td&gt;
&lt;td&gt;12 bars ≈ 2 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Win rate at 2× fees&lt;/td&gt;
&lt;td&gt;69.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BTC / ETH / SOL win rate&lt;/td&gt;
&lt;td&gt;83% / 75% / 100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two details deserve a second look. First, &lt;strong&gt;the OOS win rate is &lt;em&gt;higher&lt;/em&gt; than the in-sample one&lt;/strong&gt; — overfit strategies show the opposite signature: brilliant in the tuning window, collapsing the moment data is unfamiliar. Second, the edge survives fees at two to three times what a normal spot account pays.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1fqexrt4niqr82csua4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1fqexrt4niqr82csua4.webp" alt="Statistics grid and the full trade list for the BTC run" width="799" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying hard to break it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Six consecutive time slices&lt;/strong&gt; scored separately: win rates 71%, 56%, 62%, 55%, 69%, 75% — every window above 50%. A regime-dependent fluke does not do that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameter plateau.&lt;/strong&gt; Defaults (20 bars, 2σ, MA100) sit in the middle of a plateau: 1.8σ–2.5σ all won 70–77%, neighbouring trend filters (50–200) all stayed positive. If performance collapses when you nudge a parameter 10%, you found noise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split-date sensitivity.&lt;/strong&gt; Moving the walk-forward cut across 50/30 → 90/10 changed the aggregate win rate only between 55% and 66%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit shoot-outs.&lt;/strong&gt; Adding a 10-bar-low emergency exit or a trend-break exit &lt;em&gt;lowered&lt;/em&gt; the OOS win rate (61.5% and 51.0%). The boring mid-band exit won — stops were selling into the very wicks the strategy profits from reverting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmarks:&lt;/strong&gt; the best of the nine existing strategies managed a 51% OOS win rate on the same data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where it loses — read this part
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;73.6% win rate is not a money printer.&lt;/strong&gt; The median winner is small (+1.2%) because the target — the mid band — is close. The profile is many small wins, occasional runners, occasional give-backs. The worst held-out trade lost 16.7%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No formula stop means tail exposure exists.&lt;/strong&gt; Historically the MA100 filter and mid-band exit capped the damage, but a coin that breaks down mid-trade holds until it recovers to the mid band. If that worries you, set the optional stop in the backtester and accept slightly worse expected numbers for a hard floor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The held-out window is one market regime&lt;/strong&gt; (~5 months per coin, dips inside an uptrend). In a full bear market the MA100 filter will simply keep the strategy flat for long stretches — designed behavior, not a bonus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Survivorship bias is real&lt;/strong&gt; — today's top-40 list excludes the coins that died.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Run it across the whole market
&lt;/h2&gt;

&lt;p&gt;One coin's backtest is an anecdote. The &lt;a href="https://chartcrypto.app/scanner/trend-dip" rel="noopener noreferrer"&gt;scanner page&lt;/a&gt; runs the identical formula across a whole universe in one pass — each coin split walk-forward, ranked by out-of-sample Sharpe:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftlzou59c1p0lvj4dmi41.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftlzou59c1p0lvj4dmi41.webp" alt="Multi-coin scanner running Trend Dip across the top-20 universe" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the hood (the dev part)
&lt;/h2&gt;

&lt;p&gt;The whole thing — formula parser, indicator engine, backtest simulator, walk-forward scanner — is a Rust→WASM module evaluated entirely in your browser on real exchange candles. The strategy DSL is a tiny TDX-style language (&lt;code&gt;ENTRY:CROSS(C,LOWER) &amp;amp;&amp;amp; C&amp;gt;TRENDMA;&lt;/code&gt;), so every rule on the site is user-editable text, and the simulator fills at the next bar's open with configurable fees and slippage. Nothing you type is uploaded anywhere.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-run this exact strategy on any pair: &lt;a href="https://chartcrypto.app/backtesting/trend-dip" rel="noopener noreferrer"&gt;backtest page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Scan the whole universe: &lt;a href="https://chartcrypto.app/scanner/trend-dip" rel="noopener noreferrer"&gt;scanner page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Full write-up with more stress tests: &lt;a href="https://chartcrypto.app/blog/trend-dip-indicator-design" rel="noopener noreferrer"&gt;original article&lt;/a&gt; &lt;em&gt;(canonical URL of this post — it's the same article, cross-posted)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; everything above is a historical backtest, not a promise. Backtested win rates decay in live trading. Not financial advice — crypto is volatile and you can lose your entire investment.&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>trading</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Testing automata-theory exercises in the browser: a regex flavor for CS coursework</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Sun, 04 Oct 2026 12:19:22 +0000</pubDate>
      <link>https://dev.to/easy28/testing-automata-theory-exercises-in-the-browser-a-regex-flavor-for-cs-coursework-3kio</link>
      <guid>https://dev.to/easy28/testing-automata-theory-exercises-in-the-browser-a-regex-flavor-for-cs-coursework-3kio</guid>
      <description>&lt;p&gt;If you've ever taught or taken a formal languages course, you know the workflow: the exercise says &lt;em&gt;write a regular expression for all strings over {a,b} containing an even number of a's&lt;/em&gt;, you write &lt;code&gt;(b|ab)*&lt;/code&gt; on paper... and then you have no way to check it.&lt;/p&gt;

&lt;p&gt;Programming regex flavors can't validate it for you — they're full of conveniences the formal dialect doesn't have: character classes, quantifier shorthands, anchors. What you want is a checker that speaks the &lt;strong&gt;textbook dialect&lt;/strong&gt;: union &lt;code&gt;∪&lt;/code&gt; or &lt;code&gt;|&lt;/code&gt;, concatenation, Kleene star &lt;code&gt;*&lt;/code&gt;, plus &lt;code&gt;+&lt;/code&gt;, parentheses. Nothing more.&lt;/p&gt;

&lt;p&gt;RegexTester.dev now ships a &lt;strong&gt;Formal Automata Theory flavor&lt;/strong&gt; exactly for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it accepts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Symbols from your chosen alphabet (typically &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, or &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Union: &lt;code&gt;∪&lt;/code&gt; or &lt;code&gt;|&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Concatenation: juxtaposition or &lt;code&gt;.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Kleene star: &lt;code&gt;*&lt;/code&gt;, and one-or-more: &lt;code&gt;+&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Grouping with parentheses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else — &lt;code&gt;\d&lt;/code&gt;, &lt;code&gt;[a-z]&lt;/code&gt;, lookahead, backreferences — is rejected with an explanation, because the point is to exercise exactly the constructs the course covers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instant feedback
&lt;/h2&gt;

&lt;p&gt;Type the expression and test strings in, and you immediately see which strings match and which don't — so you can iterate on the exercise instead of waiting for a grader.&lt;/p&gt;

&lt;p&gt;The flavor runs on the same engine infrastructure as the other eight dialects (PCRE2, RE2, .NET, Python, Java, Go, Rust, JavaScript), so the matching behavior is well-defined and consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a browser tool for coursework?
&lt;/h2&gt;

&lt;p&gt;Because the feedback loop is everything when learning. The gap between writing &lt;code&gt;(b|ab)*&lt;/code&gt; on paper and knowing whether it's right is where most of the confusion in a formal languages course lives. Close that gap to seconds and students experiment their way to understanding: they can &lt;em&gt;see&lt;/em&gt; that &lt;code&gt;(b|ab)*&lt;/code&gt; matches &lt;code&gt;babb&lt;/code&gt; but not &lt;code&gt;abab&lt;/code&gt;, and fix their mental model immediately.&lt;/p&gt;

&lt;p&gt;It also works the other direction: instructors can build exercise sets with permalinks — every regex and test string combination in the tester has a shareable URL, so "check your answer against this" becomes a link.&lt;/p&gt;




&lt;p&gt;Try it: open &lt;a href="https://regextester.dev" rel="noopener noreferrer"&gt;regextester.dev&lt;/a&gt;, pick the &lt;strong&gt;Formal Automata&lt;/strong&gt; flavor from the selector, and test that even-number-of-a's exercise.&lt;/p&gt;

&lt;p&gt;Full write-up: &lt;a href="https://regextester.dev/blog/Formal-automata-theory-flavor" rel="noopener noreferrer"&gt;regextester.dev/blog/Formal-automata-theory-flavor&lt;/a&gt;. Free, no signup — built for students and educators.&lt;/p&gt;

</description>
      <category>regex</category>
      <category>computerscience</category>
      <category>education</category>
      <category>theory</category>
    </item>
  </channel>
</rss>
