<?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 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>
    <item>
      <title>Benchmarking regex patterns properly: P95/P99, equivalence checks, real engines</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Sun, 04 Oct 2026 12:08:30 +0000</pubDate>
      <link>https://dev.to/easy28/benchmarking-regex-patterns-properly-p95p99-equivalence-checks-real-engines-1cij</link>
      <guid>https://dev.to/easy28/benchmarking-regex-patterns-properly-p95p99-equivalence-checks-real-engines-1cij</guid>
      <description>&lt;p&gt;Every developer has been here: two regex patterns that both work. One is a dense one-liner, the other reads like prose. Which do you ship?&lt;/p&gt;

&lt;p&gt;"Use the simpler one" is a fine heuristic until the pattern runs over a 50 MB log file or every request in a hot path. Then you want data. The problem is that regex benchmarks done casually lie to you three ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The engine problem&lt;/strong&gt; — your JS benchmark measures JavaScript's RegExp, but the pattern ships to a PCRE2-based backend. Different engine, different behavior, different speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The clock problem&lt;/strong&gt; — a fast regex finishes in microseconds, far below &lt;code&gt;performance.now()&lt;/code&gt; resolution. You're measuring timer noise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The equivalence problem&lt;/strong&gt; — the faster pattern is faster &lt;em&gt;because it matches less&lt;/em&gt;. You optimized a bug.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;RegexTester.dev's built-in &lt;a href="https://regextester.dev/bench" rel="noopener noreferrer"&gt;Benchmark Suite&lt;/a&gt; was designed against those three traps. Here's how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real engines, identical conditions
&lt;/h2&gt;

&lt;p&gt;Up to 5 alternative patterns run sequentially under identical input, flags and engine — the same engines the tester itself uses: PCRE2 and RE2 as WebAssembly in a dedicated worker, .NET's &lt;code&gt;System.Text.RegularExpressions&lt;/code&gt; as a real interpreter, and native JS RegExp (including the normalize-to-JS path used for Python, Java and other flavors).&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%2Fnqqf6buhrj9rgna7uzxn.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%2Fnqqf6buhrj9rgna7uzxn.webp" alt="Benchmark setup" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sub-clock-precision timing
&lt;/h2&gt;

&lt;p&gt;Each sample times &lt;strong&gt;K consecutive executions&lt;/strong&gt; and records time ÷ K, with K auto-calibrated so every sample spans between 0.35 ms and 12 ms. This batch amplification resolves sub-microsecond patterns with sub-nanosecond effective resolution — far below browser clock precision.&lt;/p&gt;

&lt;p&gt;You get median, mean, P95, P99, ops/sec and the relative speedup of the fastest pattern, with a ±RSE column that tells you when a number is too noisy to trust.&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%2Frtubrg6maeddkcplsjkd.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%2Frtubrg6maeddkcplsjkd.webp" alt="Results table" width="800" height="945"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Equivalence checking
&lt;/h2&gt;

&lt;p&gt;Speed means nothing if the output changed. The suite records each pattern's match count on the benchmark input and raises an &lt;strong&gt;"Output differs"&lt;/strong&gt; warning when counts diverge — a pattern that's faster because it matches less gets flagged before you ship it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the charts
&lt;/h2&gt;

&lt;p&gt;Latency histograms and timelines make the distribution shape visible: a tight spike means stable performance; a long tail means some inputs hit pathological backtracking even when the median looks fine.&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%2F0j0c8rbmtcseze59lwem.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%2F0j0c8rbmtcseze59lwem.webp" alt="Charts" width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Export
&lt;/h2&gt;

&lt;p&gt;Results export as Markdown (for PRs and docs) or JSON (for your own tooling), with the environment (UA, cores, timestamp) baked in so numbers stay comparable.&lt;/p&gt;




&lt;p&gt;Try it: open &lt;a href="https://regextester.dev/bench" rel="noopener noreferrer"&gt;regextester.dev/bench&lt;/a&gt;, paste two alternatives, press Run. Sixty seconds later you'll know which one to ship — and whether they really do the same thing.&lt;/p&gt;

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

</description>
      <category>regex</category>
      <category>benchmarking</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I built a regex debugger that shows every backtrack (flame graph included)</title>
      <dc:creator>FF</dc:creator>
      <pubDate>Sun, 04 Oct 2026 12:08:29 +0000</pubDate>
      <link>https://dev.to/easy28/i-built-a-regex-debugger-that-shows-every-backtrack-flame-graph-included-g5e</link>
      <guid>https://dev.to/easy28/i-built-a-regex-debugger-that-shows-every-backtrack-flame-graph-included-g5e</guid>
      <description>&lt;p&gt;Testers tell you &lt;em&gt;what&lt;/em&gt; a regex matches. A debugger tells you &lt;em&gt;why&lt;/em&gt; — and &lt;em&gt;where it burns time&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Every regex tester shows the same three things: matches, groups, and an explanation of the pattern. That covers the happy path. It stops helping the moment a regex is &lt;em&gt;almost&lt;/em&gt; right — matching one tag too many, missing a case you can't reproduce, or taking 400 ms on an input that looks identical to the one that took 4.&lt;/p&gt;

&lt;p&gt;The failure modes of a backtracking engine are invisible from the outside. A pattern doesn't slowly get slower — it tries a prefix, gives characters back, retries the inner quantifier at a different split, fails, and repeats that a few thousand times. The match result looks the same as the fast version's. Only the &lt;strong&gt;trace&lt;/strong&gt; of what the engine actually did tells them apart.&lt;/p&gt;

&lt;p&gt;So I built a full debugger into &lt;a href="https://regextester.dev" rel="noopener noreferrer"&gt;RegexTester.dev&lt;/a&gt;. Here's what it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  One click from the tester
&lt;/h2&gt;

&lt;p&gt;The entry point is the &lt;strong&gt;Debug&lt;/strong&gt; button on the tester toolbar. Hit it, and the debugger opens with the trace already recorded. The demo pattern &lt;code&gt;&amp;lt;([a-z]+)([^&amp;lt;]+)*(?:&amp;gt;(.*)&amp;lt;\/\1&amp;gt;|\s+/&amp;gt;)&lt;/code&gt; against &lt;code&gt;&amp;lt;div&amp;gt;Content&amp;lt;/div&amp;gt;&lt;/code&gt; generates &lt;strong&gt;7,530 execution steps&lt;/strong&gt; for 18 characters of input. That gap between "looks simple" and "7,530 steps" is exactly what the debugger makes visible.&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%2Fzg3jdbik9gqut0a891sl.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%2Fzg3jdbik9gqut0a891sl.webp" alt="Regex debugger overview" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The execution graph
&lt;/h2&gt;

&lt;p&gt;The graph is a flame-chart of the engine's work. Each bar is one node attempt — a TRY that ended in OK (green), FAIL (red), or was undone by backtracking (thin blue give-back marks). Rows are stack depth; vertical bands separate match attempts.&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%2F4q1ajn78wzzd16rxq2ai.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%2F4q1ajn78wzzd16rxq2ai.webp" alt="Execution graph" width="797" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It behaves like a proper profiler view: scroll-wheel zoom, drag to pan, double-click to zoom to a block, click any block to jump there — the amber marker follows, and every other panel updates in lockstep. A healthy trace reads as a calm staircase. A sick one shows the signature immediately: one region of the graph orders of magnitude wider than everything else, striped with red and blue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hot spots: where the steps go
&lt;/h2&gt;

&lt;p&gt;The Hot spots table is the profiler summary: every node of your pattern, ranked, with its operation count, give-backs, failures, and share of total steps.&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%2Fshmofmilggsj5bfenba5.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%2Fshmofmilggsj5bfenba5.webp" alt="Hot spots table" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the same workflow you'd use on slow code: profile, find the hot function, fix, re-profile. It just didn't exist for regular expressions in a browser before.&lt;/p&gt;

&lt;h2&gt;
  
  
  From diagnosis to fix in two clicks
&lt;/h2&gt;

&lt;p&gt;Diagnosis without a fix is only half a tool. The &lt;strong&gt;Suggestions&lt;/strong&gt; panel combines static analysis with trace statistics to propose concrete rewrites — dialect-aware, so a PCRE2 pattern gets atomic groups and possessive quantifiers while a JavaScript pattern gets the constructs ES2025 actually supports.&lt;/p&gt;

&lt;p&gt;The classic case: &lt;code&gt;(a+)+b&lt;/code&gt; on &lt;code&gt;aaaaaaaaaaX&lt;/code&gt; — the textbook catastrophic backtracking example. The debugger names the disease and prescribes the cure:&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%2Fbgqilqkba4s8qu7zxlle.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%2Fbgqilqkba4s8qu7zxlle.webp" alt="Suggestions panel" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two things make this safe to trust:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Equivalence checking&lt;/strong&gt; — both patterns run against the real engine for your dialect on your input; only identical match lists earn the "same matches on this input" badge. A faster regex that matches less is a bug, not an optimization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply&lt;/strong&gt; writes the rewrite into the tester and re-traces immediately: same input, Healthy verdict, 404 steps instead of 50,000+.&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%2Fjgcr6bx5h1q95zdk2wvn.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%2Fjgcr6bx5h1q95zdk2wvn.webp" alt="After applying the rewrite" width="797" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A tracer kept honest
&lt;/h2&gt;

&lt;p&gt;The trace comes from an instrumented backtracking engine — a continuation-passing matcher written for this purpose, speaking the semantics of nine flavor dialects. Every trace is &lt;strong&gt;cross-checked against the real thing&lt;/strong&gt;: the match outcome is compared with the actual engine for the selected flavor (native RegExp, or PCRE2/.NET compiled to WebAssembly), and a "trace verified" badge only appears when they agree.&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://regextester.dev/debug" rel="noopener noreferrer"&gt;regextester.dev/debug&lt;/a&gt; — or read the full write-up at &lt;a href="https://regextester.dev/blog/regex-debugger" rel="noopener noreferrer"&gt;regextester.dev/blog/regex-debugger&lt;/a&gt;. Free, no signup, everything runs locally.&lt;/p&gt;

</description>
      <category>regex</category>
      <category>debugging</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
