<?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</title>
    <description>The most recent home feed on DEV Community.</description>
    <link>https://dev.to</link>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed"/>
    <language>en</language>
    <item>
      <title>HTML lang and SEO: Check the Language Your Page Declares</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:46:59 +0000</pubDate>
      <link>https://dev.to/urielbitton/html-lang-and-seo-check-the-language-your-page-declares-2pm7</link>
      <guid>https://dev.to/urielbitton/html-lang-and-seo-check-the-language-your-page-declares-2pm7</guid>
      <description>&lt;p&gt;Set the HTML lang attribute to describe the page’s actual predominant language. Then verify that the delivered page and its language label agree. This helps users and assistive technology; it should not be presented as a command that makes Google detect a language or target a country.&lt;/p&gt;

&lt;p&gt;Google explicitly says it uses algorithms, rather than HTML lang or hreflang, to detect a page’s language. That makes the technical diagnosis more precise: a wrong language label is worth fixing, but an unwanted search-language result needs its own investigation. Do not promise that changing the attribute will resolve both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep three observations separate
&lt;/h2&gt;

&lt;p&gt;Take a fictional documentation page intended for French-speaking readers. Its route contains a French-looking path, most of its explanatory text is French, but a shared layout still declares English on the root HTML element. These are three different observations: route naming, visible language, and programmatic language.&lt;/p&gt;

&lt;p&gt;The mismatch is not repaired by pointing at the URL and saying the language is obvious. A person can infer meaning from the page while a user agent receives a different label. Equally, a French label on an untranslated English page would not make that page French.&lt;/p&gt;

&lt;p&gt;Before changing anything, record the exact public URL and what the page currently delivers. Keep regional audience requirements separate from language correctness. A page can be written in French for readers in several countries, or use the same language across regional variants with different commercial conditions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visible content: what language dominates the actual answer?&lt;/li&gt;
&lt;li&gt;Declared language: what does the root HTML element identify?&lt;/li&gt;
&lt;li&gt;Audience and variants: who is the page for, and which related versions exist?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understand what the language label helps readers do
&lt;/h2&gt;

&lt;p&gt;W3C’s &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/language-of-page.html" rel="noopener noreferrer"&gt;Language of Page explanation&lt;/a&gt; describes identifying the default human language so user agents and assistive technologies can present content appropriately. Screen readers can use the correct pronunciation rules. This is a user-facing reason to provide an accurate label, independent of a ranking claim.&lt;/p&gt;

&lt;p&gt;Apply that purpose to the fictional page. If its main answer is French, a default English label is a defect to investigate in the template or localization pipeline. Correcting it helps the programmatic description match what the reader receives.&lt;/p&gt;

&lt;p&gt;A non-empty value alone is not a complete quality check. The label also needs to represent the content. A quick automated check can flag a missing attribute while missing a plausible but incorrect value inherited from another route. Include an editorial review of the visible language when verifying a translated page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspect the document that actually reaches the browser
&lt;/h2&gt;

&lt;p&gt;Open the public route directly, rather than reaching it only through an already localized session. In browser developer tools, inspect the root HTML element and read its lang value. Compare it with the main text, headings, navigation, and any important notices. Save the route and the observation date.&lt;/p&gt;

&lt;p&gt;Then follow a normal internal navigation path to the same page. If the site changes content without loading a whole document, check the language label again after navigation. A correct initial document does not establish that the attribute stays correct during every route transition.&lt;/p&gt;

&lt;p&gt;In the hypothetical docs site, direct loading might deliver the expected French label while a client-side transition leaves the previous page’s English value behind. That is a proposed failure case to test, not an observed result from a real site. If it occurs, the repair belongs in the route or layout behavior that owns the value.&lt;/p&gt;

&lt;p&gt;Also review the state a new visitor receives. Do not let yesterday’s language selection stand in for the default experience. Record any visible preference or account condition that changes what is served. This turns the check into a reproducible observation rather than an unexplained screenshot of one session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle mixed-language content deliberately
&lt;/h2&gt;

&lt;p&gt;A translated article may retain a product name, a quoted phrase, or an original-language example. Those fragments do not necessarily change the predominant language of the document. Start with the main answer and consider what a reader is actually being asked to understand.&lt;/p&gt;

&lt;p&gt;W3C’s guidance explains choosing the language used most when a page contains several languages, with the first used as the default when languages are used equally. Its related guidance addresses language changes within parts of a page. Keep document-level and passage-level labeling as separate review tasks.&lt;/p&gt;

&lt;p&gt;For a practical handoff, identify the mixed-language passage and ask whether its treatment is intentional. A long untranslated warning is a different problem from a short product name. If a critical limitation remains in another language, adding a label does not substitute for translating the information the intended audience needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Google’s language guidance within its scope
&lt;/h2&gt;

&lt;p&gt;Google’s &lt;a href="https://developers.google.com/search/docs/specialty/international/localized-versions" rel="noopener noreferrer"&gt;localized-pages documentation&lt;/a&gt; says hreflang describes relationships among localized variations. It separately states that Google does not use hreflang or the HTML lang attribute to detect the language of a page. Avoid collapsing these jobs into a single “language tag” repair.&lt;/p&gt;

&lt;p&gt;In the fictional site, fixing the English root label on the French page addresses a real mismatch. If search still shows an English version for a particular query, that is a separate observation. Inspect the actual result, relevant page content, and variant setup instead of repeatedly changing the root label.&lt;/p&gt;

&lt;p&gt;The same caution applies to AI visibility. A correct lang value is not a documented universal requirement for being cited by ChatGPT, Claude, or Gemini. Do not generalize Google’s language-detection statement into a claim about every system either. State the engine, the behavior documented, and the limit of the evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review representative routes, not one successful screenshot
&lt;/h2&gt;

&lt;p&gt;Build a small review set from the templates that can produce different language states. Include a directly loaded translated article, a page reached from another language, a fallback page, and an important error or access notice. Use the routes your product actually exposes.&lt;/p&gt;

&lt;p&gt;For each case, record intended language, observed main-content language, declared root language, and relevant navigation state. Add whether the result was checked before and after client navigation. Keep expected and observed values in separate fields so the chosen implementation cannot quietly redefine the requirement.&lt;/p&gt;

&lt;p&gt;Ask the responsible developer or localization owner to explain which component owns the value. A shared shell, server template, and route-level change can otherwise overwrite each other. The acceptance check should include the affected transitions, not just the single page used to discover the defect.&lt;/p&gt;

&lt;p&gt;A representative sample still has limits. It does not prove that every route and language combination works. Record untested templates and prioritize ones that carry important buyer answers. The goal is a clear, bounded check that another person can repeat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the repair against the problem it was meant to solve
&lt;/h2&gt;

&lt;p&gt;After the normal authorized release, reopen the public routes and repeat the recorded transitions. Confirm that the label agrees with the intended main-content language and that the content itself has not fallen back to an unexpected version. Keep evidence of the actual delivered state.&lt;/p&gt;

&lt;p&gt;If the change also affects pronunciation or other assistive behavior, use an appropriate accessibility review rather than inferring the whole experience from one attribute. A corrected label is one part of a usable multilingual page.&lt;/p&gt;

&lt;p&gt;Track search presentation and AI answers separately if those are part of the project. Save the question or query, surface, date, mode, and linked destination; repeat observations before claiming a stable change. The defensible immediate result is that a defined set of pages now declares the language it actually presents. That is useful technical work even when no discovery gain has yet been demonstrated.&lt;/p&gt;

&lt;p&gt;Hey I'm Uriel Bitton. I write about SEO, AEO, GEO, and helping brands get found in AI answers.&lt;/p&gt;

&lt;p&gt;Subscribe for practical ways to grow your brand's visibility in search and AI answers.&lt;/p&gt;

&lt;p&gt;Explore &lt;a href="https://honeywerank.com/" rel="noopener noreferrer"&gt;HoneyWeRank&lt;/a&gt; for SEO and AI visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/language-of-page.html" rel="noopener noreferrer"&gt;W3C WAI: Understanding Language of Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/search/docs/specialty/international/localized-versions" rel="noopener noreferrer"&gt;Google Search: Localized versions of your pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>html</category>
      <category>a11y</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Choosing the right API gateway can make a huge difference in routing, security, and performance. A useful comparison for developers looking to simplify API management and avoid common routing headaches.</title>
      <dc:creator>Michael Johnson</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:46:32 +0000</pubDate>
      <link>https://dev.to/michaeljohnsondz/choosing-the-right-api-gateway-can-make-a-huge-difference-in-routing-security-and-performance-a-3ek1</link>
      <guid>https://dev.to/michaeljohnsondz/choosing-the-right-api-gateway-can-make-a-huge-difference-in-routing-security-and-performance-a-3ek1</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/devstackhub/6-best-api-gateways-for-developers-breaking-their-routing-logic-4a99" class="crayons-story__hidden-navigation-link"&gt;6 Best API Gateways for Developers Breaking Their Routing Logic&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/devstackhub" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4081963%2F9d10c5fa-c76e-4c9d-88af-e3f2fced5a62.jpg" alt="devstackhub profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/devstackhub" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Dev Stack Hub
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Dev Stack Hub
                
                
              
              &lt;div id="story-author-preview-content-4953228" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/devstackhub" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4081963%2F9d10c5fa-c76e-4c9d-88af-e3f2fced5a62.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Dev Stack Hub&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/devstackhub/6-best-api-gateways-for-developers-breaking-their-routing-logic-4a99" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 31&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/devstackhub/6-best-api-gateways-for-developers-breaking-their-routing-logic-4a99" id="article-link-4953228"&gt;
          6 Best API Gateways for Developers Breaking Their Routing Logic
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/discuss"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;discuss&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/api"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;api&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/backend"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;backend&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/devstackhub/6-best-api-gateways-for-developers-breaking-their-routing-logic-4a99" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;19&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/devstackhub/6-best-api-gateways-for-developers-breaking-their-routing-logic-4a99#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              5&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            19 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>api</category>
      <category>architecture</category>
      <category>backend</category>
      <category>performance</category>
    </item>
    <item>
      <title>ASP.NET Core 'Error Unprotecting the Session Cookie': Why Your Keys Disappear on Deploy</title>
      <dc:creator>Kausar Raza</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:45:25 +0000</pubDate>
      <link>https://dev.to/kausarraza/aspnet-core-error-unprotecting-the-session-cookie-why-your-keys-disappear-on-deploy-42fe</link>
      <guid>https://dev.to/kausarraza/aspnet-core-error-unprotecting-the-session-cookie-why-your-keys-disappear-on-deploy-42fe</guid>
      <description>&lt;p&gt;You deploy an ASP.NET Core app, or IIS recycles its app pool overnight, and the log fills up with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warn: Microsoft.AspNetCore.Session.SessionMiddleware[7]
      Error unprotecting the session cookie.
      System.Security.Cryptography.CryptographicException: The key {83f2e736-3392-4263-9f0f-ad943c51fe3e} was not found in the key ring.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the same time, users report being logged out, and forms fail with "The antiforgery token could not be decrypted". The session warning is just the visible part. The cause is that the app has &lt;strong&gt;lost the keys it used to encrypt its cookies&lt;/strong&gt;. Every cookie issued before that moment is now unreadable.&lt;/p&gt;

&lt;p&gt;This happened on the API behind this site. It runs on IIS under Plesk, where the app pool has no loaded user profile, so ASP.NET Core kept its keys in memory and threw them away on every restart. Below is what I reproduced, the exact messages each cause produces, and the fix. The deploy side of IIS and Plesk 500 errors is in &lt;a href="https://knowledgemarkg.com/blog/deploy-aspnet-core-plesk-500-errors" rel="noopener noreferrer"&gt;the Plesk 500 errors post&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The short fix:&lt;/strong&gt; store the Data Protection keys in a folder that survives restarts and deploys, and give the app a fixed name: &lt;code&gt;services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(@"App_Data\keys")).SetApplicationName("MyApp")&lt;/code&gt;. Then make sure your deploy never deletes that folder. Users who already have old cookies will be logged out once more, and after that it stops.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What the error actually means
&lt;/h2&gt;

&lt;p&gt;ASP.NET Core doesn't store session data, login tickets or antiforgery tokens in plain text. It encrypts them with the &lt;strong&gt;Data Protection&lt;/strong&gt; system, which keeps a set of keys called the &lt;em&gt;key ring&lt;/em&gt;. Each encrypted payload carries the ID of the key that made it. When a request comes in, the app looks up that ID in its ring. If it isn't there, you get "The key {...} was not found in the key ring".&lt;/p&gt;

&lt;p&gt;Three components report it, in three different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session middleware&lt;/strong&gt; logs "Error unprotecting the session cookie" as a warning, then quietly starts a new, empty session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie authentication&lt;/strong&gt; logs "Cookies was not authenticated. Failure message: Unprotect ticket failed", but only at Information level. With the default &lt;code&gt;"Microsoft.AspNetCore": "Warning"&lt;/code&gt; setting in &lt;code&gt;appsettings.json&lt;/code&gt;, you never see it. The user is just signed out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Antiforgery&lt;/strong&gt; throws &lt;code&gt;AntiforgeryValidationException&lt;/code&gt;: "The antiforgery token could not be decrypted", which usually surfaces as a 400 on form posts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's why the session warning is the one people search for. It's the only one that shows up in a default log, even though the logouts hurt more.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tested
&lt;/h2&gt;

&lt;p&gt;I built a minimal ASP.NET Core 9 app (runtime 9.0.8, Windows 11, Kestrel) with cookie sign-in, session and antiforgery. I signed in with curl, kept the cookie jar, restarted the app with a different key setup each time, and sent the old cookies back. These are the results.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Keys persisted, plain restart: nothing breaks
&lt;/h3&gt;

&lt;p&gt;With keys stored in a folder and the app restarted on the same folder, the user was still signed in and the old antiforgery token still validated. This is the control. One thing did reset: the session value was empty after the restart. That isn't a key problem. &lt;code&gt;AddDistributedMemoryCache()&lt;/code&gt; keeps session data in process memory, so a restart loses it even when the cookie decrypts fine. If you need sessions to survive restarts, use SQL Server or Redis for the session store as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Key folder wiped: "was not found in the key ring"
&lt;/h3&gt;

&lt;p&gt;Pointing the restarted app at an &lt;em&gt;empty&lt;/em&gt; folder is exactly what a deploy does when it deletes the old site folder, including &lt;code&gt;App_Data&lt;/code&gt;. The user came back anonymous, the antiforgery post failed with "The antiforgery token could not be decrypted", and the log showed the error from the top of this article, naming the old key's ID. The app also silently created a new key, logging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No XML encryptor configured. Key {53f0f160-...} may be persisted to storage in unencrypted form.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Same keys, different application name: "The payload was invalid"
&lt;/h3&gt;

&lt;p&gt;Data Protection isolates apps from one another using an application name. If you don't set one, it is derived from the app's content root path. So moving the site to a different folder, or swapping deployment slots, can change it. I kept the same key folder and changed only &lt;code&gt;SetApplicationName&lt;/code&gt; from &lt;code&gt;SiteA&lt;/code&gt; to &lt;code&gt;SiteB&lt;/code&gt;. The keys were found, but nothing decrypted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warn: Microsoft.AspNetCore.Session.SessionMiddleware[7]
      Error unprotecting the session cookie.
      System.Security.Cryptography.CryptographicException: The payload was invalid.
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[7]
      Cookies was not authenticated. Failure message: Unprotect ticket failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The antiforgery error changed too, to "The required antiforgery cookie ".AspNetCore.Antiforgery.6asUPwDiMTw" is not present". The suffix of that cookie name is derived from the application name, so the app was looking for a cookie with a different name. If you see "payload was invalid" rather than "key not found", look at the application name before the keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Where the keys go by default
&lt;/h3&gt;

&lt;p&gt;With no configuration, a normal Windows user account gets this at startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User profile is available. Using 'C:\Users\&amp;lt;you&amp;gt;\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's why it works on your machine. An IIS app pool doesn't have that folder unless "Load User Profile" is on, and on shared hosting such as Plesk you often can't control that setting. When there is no profile and no registry hive set up for the pool, the framework uses an in-memory ring. I couldn't reproduce that fallback outside IIS, but its warning is in the framework itself (&lt;code&gt;Microsoft.AspNetCore.DataProtection.dll&lt;/code&gt;, 9.0.8):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neither user profile nor HKLM registry available. Using an ephemeral key repository. Protected data will be unavailable when application exits.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that line is in your startup log, every app pool recycle, idle timeout and deploy logs your users out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Three settings, all in &lt;code&gt;Program.cs&lt;/code&gt; before &lt;code&gt;builder.Build()&lt;/code&gt;. This is the configuration this site's API uses now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;keysDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DirectoryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFullPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"App_Data/keys"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContentRootPath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;keysDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dataProtection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDataProtection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PersistKeysToFileSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keysDir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;// keys survive restarts and recycles&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetApplicationName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyApp"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;              &lt;span class="c1"&gt;// fixed, so moving the folder or slot doesn't change it&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OperatingSystem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsWindows&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;dataProtection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ProtectKeysWithDpapi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;protectToLocalMachine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// encrypt key files at rest&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes on each line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The folder must be outside the release files.&lt;/strong&gt; If your deploy copies the site over &lt;code&gt;App_Data&lt;/code&gt;, or deletes and re-extracts it, the keys go with it. Keep &lt;code&gt;App_Data&lt;/code&gt; out of the delete step, the same way you keep uploads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;ProtectKeysWithDpapi(protectToLocalMachine: true)&lt;/code&gt;, not the per-user default.&lt;/strong&gt; An app pool has no user profile to hold a per-user DPAPI key. Machine scope works without one. The trade-off is that the key files can only be decrypted on the same machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set the application name once and never change it.&lt;/strong&gt; Changing it logs every user out, the same as losing the keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the change, the first deploy logs everyone out once. That's expected: the old cookies were encrypted with keys that no longer exist, and there's nothing to recover them with. From then on, restarts and recycles keep the same keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check it worked
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign in, then recycle the app pool or restart the app.&lt;/li&gt;
&lt;li&gt;Check that you are still signed in. If you are, the keys survived.&lt;/li&gt;
&lt;li&gt;Check the log. The "User profile is available" line should be gone, and no "Neither user profile nor HKLM registry available" line should appear. Either one would mean the keys went to memory.&lt;/li&gt;
&lt;li&gt;Check that &lt;code&gt;App_Data\keys&lt;/code&gt; contains &lt;code&gt;key-*.xml&lt;/code&gt; files, and that the timestamps don't change on every restart.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What does 'The key was not found in the key ring' mean in ASP.NET Core?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ASP.NET Core encrypted a cookie or token with a key that the app no longer has. The key ring is empty or missing that key, so the payload can't be decrypted. The usual cause is keys stored in memory, or a key folder that was wiped during a deploy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why am I logged out every time I deploy or recycle the app pool?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Data Protection keys are kept in memory, or in a folder that the deploy deletes. The new process has different keys, so cookies from before can't be decrypted. Persist the keys to a folder outside the release files, with PersistKeysToFileSystem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does 'The payload was invalid' mean in ASP.NET Core Data Protection?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The app found the key but the cookie still couldn't be decrypted. A common cause is a different application name. Check SetApplicationName, and check that the app isn't running from a different folder or deployment slot with a different default name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the difference between 'key not found' and 'payload was invalid'?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;'Key not found' means the key ring doesn't contain the key that encrypted the cookie, so the keys were lost or moved. 'Payload was invalid' means the key was found, but the app name or key data doesn't match. Keys first, then application name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where should ASP.NET Core store Data Protection keys on IIS?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a folder that the app pool identity can write to, outside the release folder, for example App_Data/keys. Protect the key files with ProtectKeysWithDpapi(protectToLocalMachine: true), since an app pool usually has no user profile for per-user DPAPI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does 'No XML encryptor configured' mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Data Protection keys are being saved to disk without encryption. It's a warning, not an error. Fix it with ProtectKeysWithDpapi on Windows, or with a certificate or Key Vault on other hosts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the session warning 'Error unprotecting the session cookie' mean my users are logged out?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not directly. It's the session middleware, which starts an empty session. Login is handled by cookie authentication, which logs a separate message at Information level. Check that too, because the warning alone doesn't show it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://knowledgemarkg.com/blog/error-unprotecting-session-cookie-aspnet-core" rel="noopener noreferrer"&gt;knowledgemarkg.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aspnetcore</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Verifying CVE-2026-110264 Remediation Beyond the Upgrade Button</title>
      <dc:creator>facilishz</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:45:08 +0000</pubDate>
      <link>https://dev.to/facilishz/verifying-cve-2026-110264-remediation-beyond-the-upgrade-button-2a3</link>
      <guid>https://dev.to/facilishz/verifying-cve-2026-110264-remediation-beyond-the-upgrade-button-2a3</guid>
      <description>&lt;h1&gt;
  
  
  Verifying CVE-2026-110264 Remediation Beyond the Upgrade Button
&lt;/h1&gt;

&lt;p&gt;An upgrade is a change, not yet a clean remediation result. For CVE-2026-110264, the verification question has two parts. Is every self-managed GitLab workload running a fixed release? Did the vulnerable period create evidence that the server was accessed or altered? The first answer comes from deployment records. The second requires log, identity, and downstream-system review.&lt;/p&gt;

&lt;p&gt;GitLab disclosed CVE-2026-110264 on October 21, 2026. The vulnerability is an integer overflow in regular expression compilation that, under certain conditions, could allow unauthenticated code execution on a GitLab server. GitLab rates it CVSS 10.0 and lists affected CE/EE versions from 7.0 before 18.11.13, 19.0 before 19.0.10, 19.1 before 19.1.9, 19.2 before 19.2.9, 19.3 before 19.3.6, 19.4 before 19.4.3, and 19.5 before 19.5.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confirm the software identity
&lt;/h2&gt;

&lt;p&gt;Use the fixed releases 18.11.13, 19.0.10, 19.1.9, 19.2.9, 19.3.6, 19.4.3, or 19.5.1 according to the supported branch. Confirm the reported version on every node and compare it with the package or container digest recorded by the deployment system. A load balancer may route to a node that was missed during a rolling update.&lt;/p&gt;

&lt;p&gt;Check GitLab.com and Dedicated assumptions separately from self-managed infrastructure. GitLab.com was patched. Dedicated tenants running 19.3.5-internal0 and 19.4.2-internal0 or later include these fixes. A third-party managed service needs the provider's confirmation for the specific tenant and version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the service, not just the banner
&lt;/h2&gt;

&lt;p&gt;Open a repository, render a merge request, run a small pipeline job, and perform a permitted administrative check. Confirm background workers are processing jobs and that no migration errors are recurring. In a clustered environment, verify health and version consistency across nodes.&lt;/p&gt;

&lt;p&gt;Check that the two GitLab detections, "Onigmo native worker crash" and "Org mode render error burst," continue to deliver events after the upgrade. This catches broken log collection and helps identify a workload that rolled back or was left on an older image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the exposure window
&lt;/h2&gt;

&lt;p&gt;The public advisory does not disclose the exact triggering request, so a search for one known exploit string is insufficient. Use the GitLab detections as starting points. Correlate crash and error events with web requests, worker restarts, process creation, outbound network connections, and changes to repositories or pipelines.&lt;/p&gt;

&lt;p&gt;Review audit events for new deploy keys, tokens, webhooks, runner registrations, and access changes. Inspect source and CI/CD history for modifications that could cause a later trusted build or deployment to execute attacker-controlled code. Compare package publications and release artifacts with the expected release process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle credentials and sessions
&lt;/h2&gt;

&lt;p&gt;If exploitation is credible, rotate secrets available to the GitLab application and connected services. Revoke active sessions and tokens that cannot be rotated. Coordinate with cloud, package registry, monitoring, and deployment owners so the rotation is complete rather than limited to one application setting.&lt;/p&gt;

&lt;p&gt;Keep evidence of the old and new credential state without storing the secret values in the case record. Document who completed each rotation and which dependent system accepted the new credential. Repeat the functional checks after rotation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat network controls correctly
&lt;/h2&gt;

&lt;p&gt;Restricting public access and outbound traffic can reduce exposure and limit attacker movement. These controls do not remove the vulnerable code. A WAF rule has no verified efficacy without a known request pattern, and authentication in front of the application may not cover the unauthenticated vulnerable path.&lt;/p&gt;

&lt;p&gt;CERT-EU recommends updating affected assets quickly, prioritizing internet-facing systems, and assessing for compromise. That assessment should remain open when a crash or render-error event cannot be explained, even if the software is now patched.&lt;/p&gt;

&lt;h2&gt;
  
  
  Record measurement limits
&lt;/h2&gt;

&lt;p&gt;During this review, ZoomEye returned 1,420,782 matches for &lt;code&gt;app="GitLab"&lt;/code&gt; and 111,067,840 matches for &lt;code&gt;vul.cve="CVE-2026-110264"&lt;/code&gt;. These are query results under explicit terms. They are not confirmed vulnerable installations and should not be used as a victim count.&lt;/p&gt;

&lt;p&gt;The remediation record is stronger when it includes the version and digest for each node, the date and operator of the change, functional checks, detection health, and the outcome of any compromise review. That record answers what was changed and what remains uncertain.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.gitlab.com/releases/patches/patch-release-gitlab-19-5-1-released/" rel="noopener noreferrer"&gt;GitLab Critical Patch Release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cert.europa.eu/publications/security-advisories/2026-019" rel="noopener noreferrer"&gt;CERT-EU Security Advisory 2026-019&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-110264" rel="noopener noreferrer"&gt;CVE-2026-110264&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>gitlab</category>
      <category>vulnerability</category>
    </item>
    <item>
      <title>Mocking File Downloads and Binary Responses Without Faking Them Badly</title>
      <dc:creator>Jeff</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:45:04 +0000</pubDate>
      <link>https://dev.to/jeff_pdc/mocking-file-downloads-and-binary-responses-without-faking-them-badly-2eoc</link>
      <guid>https://dev.to/jeff_pdc/mocking-file-downloads-and-binary-responses-without-faking-them-badly-2eoc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick answer:&lt;/strong&gt; Mocking JSON endpoints is straightforward, but mocking file downloads exposes a different set of assumptions: the response is a binary stream, the headers carry as much of the contract as the body, and clients behave differently depending on content length, encoding, and whether the download is chunked or interrupted. A mock that returns a base64 string or a tiny placeholder file will make the happy path pass while leaving the real failure modes—large files, partial downloads, and correct content-type negotiation—completely untested. The reliable approach is to serve real fixture bytes with the exact headers a production object store or file server returns, including content-length and content-disposition, and to add explicit cases for resumable and failed downloads. If your mock only proves the client can receive a small text blob, the first large PDF or image export in production is still an untested path.&lt;/p&gt;

&lt;p&gt;Most mock servers are optimized around JSON because that is the common API case, and a binary response is awkward to fit into the same inline-body model. Teams often work around it by embedding a short base64 string, which tests that the client requests the endpoint but not that it correctly decodes bytes, writes a file, or handles the headers that drive a browser or SDK download behavior. The endpoint returns 200, so the test goes green, while the actual download logic remains unverified.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a binary mock must reproduce
&lt;/h2&gt;

&lt;p&gt;The contract for a download is distributed across headers and body, and missing any piece changes client behavior.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;th&gt;Mock requirement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content-Type&lt;/td&gt;
&lt;td&gt;Drives handling&lt;/td&gt;
&lt;td&gt;Exact type, e.g. application/pdf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Disposition&lt;/td&gt;
&lt;td&gt;Filename and inline/attachment&lt;/td&gt;
&lt;td&gt;Set and asserted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Length&lt;/td&gt;
&lt;td&gt;Progress and buffering&lt;/td&gt;
&lt;td&gt;Real byte length&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Body bytes&lt;/td&gt;
&lt;td&gt;Decoding correctness&lt;/td&gt;
&lt;td&gt;Actual fixture file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transfer encoding&lt;/td&gt;
&lt;td&gt;Chunked vs known length&lt;/td&gt;
&lt;td&gt;Both cases covered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accept-Ranges&lt;/td&gt;
&lt;td&gt;Resumable downloads&lt;/td&gt;
&lt;td&gt;Range support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Content-Length row is where placeholder mocks fail quietly: a two-byte placeholder reports a trivial length, so progress bars, buffer sizing, and large-file memory behavior never get exercised against realistic sizes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serve real fixture bytes with exact headers
&lt;/h2&gt;

&lt;p&gt;Point the mock at an actual fixture file and return its raw bytes with the headers the production endpoint would set, rather than embedding a base64 string in the body definition.&lt;/p&gt;

&lt;p&gt;Using a real file also lets you assert the round trip: write the downloaded bytes to a temp path and compare them byte-for-byte against the fixture, which catches any accidental text decoding or base64 wrapping that would corrupt the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test ranges, large files, and interruption
&lt;/h2&gt;

&lt;p&gt;The production failures for downloads are about size and interruption, so model them explicitly: honor range requests for resumable downloads, serve a large fixture to exercise streaming and memory, and simulate a dropped connection partway through.&lt;/p&gt;

&lt;p&gt;For the interruption case, close the connection after sending a partial body and confirm the client detects the short read against the expected content length and retries or resumes rather than writing a corrupt file and reporting success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Derive the mock from the contract
&lt;/h2&gt;

&lt;p&gt;When the response schema and headers are defined in the OpenAPI contract, a generated mock can return typed binary fixtures and the correct headers consistently, including the declared content types and response codes. This keeps the download mock aligned with the real endpoint and lets the same contract drive generated clients that already know how to stream bytes to disk.&lt;/p&gt;

&lt;p&gt;The practical rule is to treat file downloads as a first-class contract rather than a quirky endpoint. Serve real fixture bytes with exact content type, disposition, and length; cover ranges, large files, and interrupted streams; and verify the downloaded bytes match the source. A mock that only returns a small base64 placeholder proves the endpoint exists, not that the client can actually download a file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why not just return a base64 string from the mock?
&lt;/h3&gt;

&lt;p&gt;That returns text the client may fail to decode correctly, and it skips the headers and realistic byte length that drive download behavior. Serve raw fixture bytes with the production headers instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which headers matter most for a download?
&lt;/h3&gt;

&lt;p&gt;Content-Type, Content-Disposition for the filename and mode, and Content-Length for progress and buffering. Range and Content-Range matter for resumable downloads.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I verify the client decoded the file correctly?
&lt;/h3&gt;

&lt;p&gt;Write the downloaded bytes to a temp file and compare them byte-for-byte against the fixture. This catches text decoding errors and accidental base64 wrapping.&lt;/p&gt;

&lt;h3&gt;
  
  
  What failure cases should the mock cover?
&lt;/h3&gt;

&lt;p&gt;Large files for streaming and memory, range requests for resumable downloads, and a connection dropped mid-stream to confirm the client detects a short read and retries rather than saving a corrupt file.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does the API contract help with binary mocks?
&lt;/h3&gt;

&lt;p&gt;It declares the response type and headers, so a generated mock serves typed binary fixtures with correct headers and generated clients know how to stream the bytes to disk.&lt;/p&gt;

&lt;p&gt;This is part of the &lt;a href="https://www.powerduck.com/blog/powerduck-vs-mockoon/" rel="noopener noreferrer"&gt;Powerduck vs Mockoon&lt;/a&gt; comparison — start there for the full picture of realistic mocking.&lt;/p&gt;

</description>
      <category>mocking</category>
      <category>api</category>
      <category>developers</category>
    </item>
    <item>
      <title>A Maintenance Request Is a Ticket: Designing Better Property Management Workflows</title>
      <dc:creator>Real Estate</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:44:22 +0000</pubDate>
      <link>https://dev.to/real_estate_miami/a-maintenance-request-is-a-ticket-designing-better-property-management-workflows-j9a</link>
      <guid>https://dev.to/real_estate_miami/a-maintenance-request-is-a-ticket-designing-better-property-management-workflows-j9a</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff2s416rhjrpgwq2josb9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff2s416rhjrpgwq2josb9.jpg" alt=" " width="516" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A tenant reports a leaking sink. Someone reads the message, contacts a plumber, arranges access, and tells the owner what happened.&lt;/p&gt;

&lt;p&gt;That sounds like a simple workflow—until the request lives in a text message, the approval sits in an email, and the invoice arrives in a different inbox.&lt;/p&gt;

&lt;p&gt;For developers, the problem is familiar: scattered state, unclear ownership, and no reliable record of what happens next.&lt;/p&gt;

&lt;p&gt;Property maintenance is a useful case study in designing software around real operational work. Here’s how we would approach the workflow as a system design exercise.&lt;/p&gt;

&lt;p&gt;Start With an Explicit State Model&lt;/p&gt;

&lt;p&gt;A single completed boolean cannot explain whether a request is waiting for approval, scheduled with a vendor, or still unassigned.&lt;/p&gt;

&lt;p&gt;A more useful starting point is a small set of explicit states:&lt;/p&gt;

&lt;p&gt;type MaintenanceStatus =&lt;br&gt;
  | "submitted"&lt;br&gt;
  | "triaged"&lt;br&gt;
  | "awaiting_approval"&lt;br&gt;
  | "ready_to_schedule"&lt;br&gt;
  | "scheduled"&lt;br&gt;
  | "in_progress"&lt;br&gt;
  | "awaiting_verification"&lt;br&gt;
  | "closed"&lt;br&gt;
  | "cancelled";&lt;/p&gt;

&lt;p&gt;Each state should answer two questions:&lt;/p&gt;

&lt;p&gt;What has happened?&lt;/p&gt;

&lt;p&gt;Who needs to act next?&lt;/p&gt;

&lt;p&gt;For example, awaiting_approval means the next action belongs to an authorized approver. awaiting_verification means reported completion still needs review.&lt;/p&gt;

&lt;p&gt;The exact labels matter less than having consistent definitions and allowed transitions. Reopening a request should also be an explicit action with a reason.&lt;/p&gt;

&lt;p&gt;Separate Urgency From Status&lt;/p&gt;

&lt;p&gt;A request’s position in the workflow does not describe its urgency.&lt;/p&gt;

&lt;p&gt;A broken cabinet handle and an active water leak might both be submitted. They should not enter the same operational queue with identical priority.&lt;/p&gt;

&lt;p&gt;Model urgency separately:&lt;/p&gt;

&lt;p&gt;interface MaintenanceRequest {&lt;br&gt;
  id: string;&lt;br&gt;
  propertyId: string;&lt;br&gt;
  unitId?: string;&lt;br&gt;
  status: MaintenanceStatus;&lt;br&gt;
  priority: "routine" | "urgent" | "emergency";&lt;br&gt;
  assignedTo?: string;&lt;br&gt;
  createdAt: string;&lt;br&gt;
  updatedAt: string;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A production system would also need attachments, access arrangements, approvals, and a history of changes.&lt;/p&gt;

&lt;p&gt;Emergency handling needs a defined human escalation process. Saving a high-priority database record is not enough to ensure someone responds.&lt;/p&gt;

&lt;p&gt;Make Approval Rules Enforceable&lt;/p&gt;

&lt;p&gt;An approval threshold should influence what the system permits.&lt;/p&gt;

&lt;p&gt;If an estimate exceeds the authorized amount, the workflow should require approval before ordinary scheduling proceeds. Any emergency exception needs its own documented authority and audit trail.&lt;/p&gt;

&lt;p&gt;Enforce these rules on the server. Hiding a button in the interface does not prevent an unauthorized transition.&lt;/p&gt;

&lt;p&gt;Approval should also apply to a specific estimate version. If the scope or price changes materially, an earlier approval should not silently authorize the new work.&lt;/p&gt;

&lt;p&gt;Expect Duplicate Messages and Failed Notifications&lt;/p&gt;

&lt;p&gt;Real workflows include retries.&lt;/p&gt;

&lt;p&gt;A tenant taps submit twice. A vendor resends a completion update. A notification service times out after accepting a message.&lt;/p&gt;

&lt;p&gt;Use idempotency keys where repeated operations could create duplicate requests or actions. Record notification delivery separately from the request’s operational status.&lt;/p&gt;

&lt;p&gt;“Email sent” and “repair scheduled” are different facts. One should never stand in for the other.&lt;/p&gt;

&lt;p&gt;Keep a History Without Building an Entire Event-Sourcing Platform&lt;/p&gt;

&lt;p&gt;A current-status field is useful for displaying the queue. An append-only activity history explains how the request reached that state.&lt;/p&gt;

&lt;p&gt;Record the actor, timestamp, action, and relevant change. Update the current state and its history entry in one transaction so they stay consistent.&lt;/p&gt;

&lt;p&gt;Access matters, too. Tenants should see their own requests. Vendors should receive only the information needed for assigned work. Owners should have visibility into properties they are authorized to access.&lt;/p&gt;

&lt;p&gt;Measure the Handoffs&lt;/p&gt;

&lt;p&gt;A dashboard showing “12 open tickets” gives limited operational insight.&lt;/p&gt;

&lt;p&gt;More useful questions include:&lt;/p&gt;

&lt;p&gt;Which requests have no assigned owner?&lt;/p&gt;

&lt;p&gt;How long have requests waited for approval?&lt;/p&gt;

&lt;p&gt;Which scheduled jobs are overdue?&lt;/p&gt;

&lt;p&gt;Which completed repairs still need verification?&lt;/p&gt;

&lt;p&gt;These views help people identify the next action.&lt;/p&gt;

&lt;p&gt;The design principle is straightforward: make responsibility visible, preserve the history, and distinguish a recorded update from a completed outcome.&lt;/p&gt;

&lt;p&gt;That applies to property maintenance—and to almost any software coordinating work between people.&lt;/p&gt;

&lt;p&gt;Winvest Management provides rental property management services in the Miami area. This article presents a conceptual software design, not a description of the company’s internal technology. Learn more at winvestmanagement.com.&lt;/p&gt;

</description>
      <category>realestate</category>
      <category>propertymanagement</category>
    </item>
    <item>
      <title>Breaking Change Detection in CI: Catching a Removed Field Before Release</title>
      <dc:creator>Jeff</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:42:07 +0000</pubDate>
      <link>https://dev.to/jeff_pdc/breaking-change-detection-in-ci-catching-a-removed-field-before-release-502a</link>
      <guid>https://dev.to/jeff_pdc/breaking-change-detection-in-ci-catching-a-removed-field-before-release-502a</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick answer:&lt;/strong&gt; Breaking API changes are rarely the result of someone intending to break clients; they are the result of a change that looks harmless in a pull request but removes or alters a field that a generated client depends on. Relying on a human review of a large OpenAPI diff is how these slip through, because the breakage is a structural comparison against the previous contract, not a judgment about the code quality. The reliable approach is to run an automated breaking-change check in CI on every spec pull request, classify the delta against the previously released version, and block merges that remove or change published operations without an explicit, reviewed exception. If the first time a breaking change is detected is a client 400 in production, the review process failed; the diff should be rejected automatically long before it ships.&lt;/p&gt;

&lt;p&gt;Documentation-focused tools are good at rendering and linting a spec, and linting catches style and structural problems inside the current document, but it cannot answer the separate question of whether this version is compatible with the last released one. That comparison is temporal: it requires two versions of the contract and a rule set for what constitutes a breaking delta, such as deleting a field, tightening a constraint, or making an optional parameter required. A clean, lint-passing spec can still be a breaking change relative to what clients already consume.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually counts as breaking
&lt;/h2&gt;

&lt;p&gt;Some changes are obviously breaking and others are quietly so, and the second category is what the CI check is for.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;th&gt;Breaking?&lt;/th&gt;
&lt;th&gt;Why clients break&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Remove an endpoint or field&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Generated calls fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Make optional field required&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Old requests rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add an optional field&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Ignored by old clients&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Narrow an enum or range&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Valid values now fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change a type or format&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Parsing assumptions break&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add a new endpoint&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Purely additive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The enum narrowing row is a classic blind spot: removing a value that existing clients still send passes linting and looks like cleanup, but it turns previously valid requests into 400s the moment the change deploys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the comparison in CI against the released contract
&lt;/h2&gt;

&lt;p&gt;The check should fetch the last released spec, compare it to the pull request version, and fail the build on any breaking rule rather than merely printing a report that a reviewer can ignore.&lt;/p&gt;

&lt;p&gt;Wiring the check to the required status means a structural break cannot be merged by accident, which is the whole point. The reviewer then sees an explicit list of breaking rules rather than having to reconstruct the delta from a raw diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Allow deliberate breaks through an explicit path
&lt;/h2&gt;

&lt;p&gt;Some breaking changes are intentional, such as a versioned API removal that was announced in advance. Those should not be silently force-merged; they should pass through a documented exception that records the approval and the migration path, so the audit trail shows the break was deliberate and clients were warned.&lt;/p&gt;

&lt;p&gt;An expiration on the suppression prevents it from becoming a permanent hole, and tying it to a specific path keeps the rest of the spec protected. The default remains to block; the exception is narrow and time-bound.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gate client generation and release on the same contract
&lt;/h2&gt;

&lt;p&gt;Because clients and mocks are generated from the same OpenAPI contract, a passing compatibility check means the generated SDKs stay safe to publish, and the diff output can feed release notes automatically. The contract is the single gate: lint for internal correctness, breaking-change detection for backward compatibility, then generation. Keeping these steps together in one pipeline prevents the situation where docs render correctly but the underlying change silently invalidates every consumer.&lt;/p&gt;

&lt;p&gt;The practical recommendation is to treat backward compatibility as an automated build gate, not a review expectation. Every spec pull request diffs against the last released contract, breaking rules fail the build, and intentional removals pass through a scoped, expiring suppression with a recorded migration. If detection depends on a reviewer noticing a deleted enum value in a thousand-line diff, clients will find the break first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is linting the spec enough to prevent breaks?
&lt;/h3&gt;

&lt;p&gt;No. Linting validates the current document's structure and style, while breaking-change detection compares two versions over time. A lint-clean spec can still remove a field that existing clients use.&lt;/p&gt;

&lt;h3&gt;
  
  
  What counts as a breaking change?
&lt;/h3&gt;

&lt;p&gt;Removing operations or fields, making an optional parameter required, narrowing enums or ranges, and changing types or formats. Additions of optional fields or new endpoints are generally safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we ship an intentional breaking change?
&lt;/h3&gt;

&lt;p&gt;Use a scoped, expiring suppression tied to the specific path with a recorded approval and migration guide, rather than disabling the check or force-merging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where should the check run?
&lt;/h3&gt;

&lt;p&gt;In CI on every spec pull request, comparing against the last released contract and blocking the merge when a breaking rule fires.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does this protect generated clients?
&lt;/h3&gt;

&lt;p&gt;Since SDKs and mocks are generated from the same contract, a passing compatibility gate guarantees the published clients remain safe, and the diff can feed release notes automatically.&lt;/p&gt;

&lt;p&gt;This is part of the &lt;a href="https://www.powerduck.com/blog/powerduck-vs-redocly/" rel="noopener noreferrer"&gt;Powerduck vs Redocly&lt;/a&gt; comparison — start there for the full picture of contract governance.&lt;/p&gt;

</description>
      <category>openapi</category>
      <category>documentation</category>
      <category>developers</category>
    </item>
    <item>
      <title>You Don't Do Your Work Alone — “Supply chain”</title>
      <dc:creator>nabbisen</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:42:00 +0000</pubDate>
      <link>https://dev.to/nabbisen/you-dont-do-your-work-alone-supply-chain-51b</link>
      <guid>https://dev.to/nabbisen/you-dont-do-your-work-alone-supply-chain-51b</guid>
      <description>&lt;p&gt;&lt;em&gt;Protecting Your Work and the Connections That Matter — Part 2&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How a product reaches the customer
&lt;/h2&gt;

&lt;p&gt;Imagine a small bakery.&lt;/p&gt;

&lt;p&gt;The owner gets up early, bakes bread, puts it on display, and sells it to customers. They buy ingredients, check the baked goods, serve customers, and keep track of sales.&lt;/p&gt;

&lt;p&gt;At first glance, it may look as though the work happens entirely between the owner and the customer.&lt;/p&gt;

&lt;p&gt;But let’s pause and think about it.&lt;/p&gt;

&lt;p&gt;To bake bread, the owner needs flour and butter. There are suppliers who deliver those ingredients. Electricity is needed to run the oven. The bakery uses a register and a payment service to sell its products. It may also use accounting software to record sales and email to communicate with business partners.&lt;/p&gt;

&lt;p&gt;Even when one person runs the whole bakery, the work does not depend on that person alone.&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%2Fy2zwb4n6rrg3sdwbtqvl.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%2Fy2zwb4n6rrg3sdwbtqvl.webp" alt="business-connections" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Our work depends on many connections
&lt;/h2&gt;

&lt;p&gt;This is not unique to bakeries.&lt;/p&gt;

&lt;p&gt;Here are some examples of the people and services that may support everyday business activities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Business activity&lt;/th&gt;
&lt;th&gt;People and services involved&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Getting products or materials&lt;/td&gt;
&lt;td&gt;Suppliers, manufacturers, delivery companies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Communicating with customers&lt;/td&gt;
&lt;td&gt;Phone, email, messaging services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Receiving reservations and orders&lt;/td&gt;
&lt;td&gt;Booking websites, order-management systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Receiving payments&lt;/td&gt;
&lt;td&gt;Banks, card issuers, payment services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handling administration and accounting&lt;/td&gt;
&lt;td&gt;Accounting software, cloud services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storing business data&lt;/td&gt;
&lt;td&gt;Computers, storage devices, backup services&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The people and services a business needs will vary. No business needs to use all of them.&lt;/p&gt;

&lt;p&gt;But many businesses rely on things they could not provide or maintain entirely on their own.&lt;/p&gt;

&lt;p&gt;Those people, companies, and services allow us to focus on our own work.&lt;/p&gt;

&lt;p&gt;In the previous article, we looked at the connections that are easy to overlook by using customer Wi-Fi as an example. Now let’s take a wider view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our work itself depends on a network of people, companies, and services.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What if one of those connections stopped working?
&lt;/h2&gt;

&lt;p&gt;These relationships are very useful in our everyday work.&lt;/p&gt;

&lt;p&gt;We can have the things we need delivered. We can communicate with people far away. We can rely on services to handle complicated calculations and records. Things that would be difficult to do alone become possible with help from other people and systems.&lt;/p&gt;

&lt;p&gt;But what would happen if one of those services suddenly became unavailable?&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A supplier’s ordering system stops working, so you cannot order the ingredients you need.&lt;/li&gt;
&lt;li&gt;A payment service has an outage, and you cannot accept card payments.&lt;/li&gt;
&lt;li&gt;You cannot access the cloud service where your accounting data is stored, so you cannot check important records.&lt;/li&gt;
&lt;li&gt;Email stops working, making it difficult to contact customers and business partners.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wouldn’t each of these situations make it difficult to run your business?&lt;/p&gt;

&lt;p&gt;Of course, these problems are not necessarily caused by cyberattacks. They can also result from equipment failures, network outages, or problems with the service provider.&lt;/p&gt;

&lt;p&gt;The important point is this: &lt;strong&gt;even when nothing has gone wrong at your own business, a problem with something that supports your work can still affect you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a supplier or a service you rely on is hit by a cyberattack, the effects may reach your business as well. An ordering or communication service might stop working, or you might no longer be able to check information needed to complete a transaction.&lt;/p&gt;

&lt;p&gt;Not every connection will immediately spread a problem to another business. But if you do not know what supports your work, it can be difficult to know what might cause trouble when something goes wrong.&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%2Fkgl6zpke8lfsieba4ps9.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%2Fkgl6zpke8lfsieba4ps9.webp" alt="interconnected-business-risk" width="800" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  This network of connections is called a “supply chain”
&lt;/h2&gt;

&lt;p&gt;Many people and companies are involved in getting a product or service to a customer.&lt;/p&gt;

&lt;p&gt;Some provide materials, others manufacture products, transport them, or sell them. Each plays a part and passes the work on to the next person or organization.&lt;/p&gt;

&lt;p&gt;This series of connections is called a &lt;strong&gt;supply chain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The term may sound technical, but the idea is familiar. It simply describes the relationships that support the work we do every day.&lt;/p&gt;

&lt;p&gt;And supply chains are not just for large corporations.&lt;/p&gt;

&lt;p&gt;A sole proprietor, a small shop, and a company with only a few employees all have their own supply chains.&lt;/p&gt;

&lt;p&gt;Being small does not mean that you can do business without depending on anyone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take a moment to think about what supports your work
&lt;/h2&gt;

&lt;p&gt;Let’s take a moment to look at your own business.&lt;/p&gt;

&lt;p&gt;From the time you start work until you deliver a product or service to a customer and receive payment, which people, companies, and services are involved?&lt;/p&gt;

&lt;p&gt;It may be enough to write down these three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;People and businesses your work depends on:&lt;/strong&gt; suppliers, business partners, outside contractors, and others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Services your work depends on:&lt;/strong&gt; email, payments, reservations, accounting, cloud services, and so on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Things that would cause trouble if they became unavailable:&lt;/strong&gt; data, equipment, communication methods, records, and so on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You do not need to identify everything at once. Just start with whatever comes to mind.&lt;/p&gt;

&lt;p&gt;Writing these things down may reveal connections that you rarely think about.&lt;/p&gt;

&lt;p&gt;Protecting your work does not mean protecting only your computer or your shop. It also means taking care of the relationships with the people and services that support your business.&lt;/p&gt;

&lt;p&gt;And because those connections exist, a problem somewhere along the way may affect you, too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the next article, we will look at what a cyberattack can really mean for a business. Having information stolen is not the only kind of damage. We will consider what happens when you can no longer keep working.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>security</category>
    </item>
    <item>
      <title>The Embedded API Playground: Interactive Requests vs Static Reference</title>
      <dc:creator>Jeff</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:39:18 +0000</pubDate>
      <link>https://dev.to/jeff_pdc/the-embedded-api-playground-interactive-requests-vs-static-reference-1l4c</link>
      <guid>https://dev.to/jeff_pdc/the-embedded-api-playground-interactive-requests-vs-static-reference-1l4c</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick answer:&lt;/strong&gt; A static API reference tells a developer what an endpoint is, and an interactive playground lets them find out what it does, and the difference shows up the moment a request needs real auth, a realistic body, or a value returned from a previous call. A pretty page of generated endpoints is cheap to produce but stops at "here is the shape"; a playground that runs against a configured environment and chains calls together turns the docs into a place where someone can actually verify integration behavior. The two are not really competitors if you can do both from one contract, but if you have to choose where the effort goes, static reference alone leaves every developer rebuilding the request in their own client to learn what the docs would not show. A playground that cannot authenticate or preserve state between calls is just a static reference with a send button glued on.&lt;/p&gt;

&lt;p&gt;Documentation platforms are often judged by how good the rendered reference looks, which is a reasonable concern for navigation and readability but a different problem from whether a new developer can successfully make a working call. Generated static pages scale automatically as the spec changes, which is their strength; their weakness is that reading a schema does not answer the questions that occupy real integration time: which header the gateway actually requires, how errors look with a live token, and what a valid combination of nested fields is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static reference versus an interactive playground
&lt;/h2&gt;

&lt;p&gt;The distinction is the kind of question each one answers, and they have different failure modes when they are the only option.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Static reference&lt;/th&gt;
&lt;th&gt;Interactive playground&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What fields exist?&lt;/td&gt;
&lt;td&gt;Answers well&lt;/td&gt;
&lt;td&gt;Also shows them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does my token work?&lt;/td&gt;
&lt;td&gt;Cannot answer&lt;/td&gt;
&lt;td&gt;Live 401/200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What is a valid body?&lt;/td&gt;
&lt;td&gt;Schema only&lt;/td&gt;
&lt;td&gt;Runs and returns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chaining two calls?&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Reuses a response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real error shape?&lt;/td&gt;
&lt;td&gt;Documented example&lt;/td&gt;
&lt;td&gt;Actual gateway error&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The chaining row is where a lot of "interactive" docs quietly fail: a playground that can send one request but cannot capture the id it returns and use it in the next call does not model a real workflow, which is almost always multi-step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bind the playground to real environments and auth
&lt;/h2&gt;

&lt;p&gt;A useful playground is configured against selectable environments and authenticates through the same schemes as production, so the response a developer sees is the one their client will get, not a canned example.&lt;/p&gt;

&lt;p&gt;Because the environment and auth come from the contract, the playground does not drift into pointing at a hardcoded demo host that no longer matches the real gateway, and the developer can switch staging and production without leaving the docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support stateful, multi-step workflows
&lt;/h2&gt;

&lt;p&gt;Let a response value be captured and referenced in a later request so the playground can walk an actual flow: create a resource, read its id, then act on it. This is the capability that moves the tool from a single-request tester to a way of learning the whole integration.&lt;/p&gt;

&lt;p&gt;Variable capture between steps is the same mechanism that makes a collection reusable, but grounded in the spec so the example and the live request never separate into two artifacts that have to be maintained by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate both from one contract
&lt;/h2&gt;

&lt;p&gt;The strongest setup avoids choosing at all: the OpenAPI contract renders the static reference for navigation and drives the interactive playground for execution, including environments, auth, and examples. Generated clients and mocks share the same source, so a developer can read the field, run the call, and then move into a generated SDK without the docs contradicting either.&lt;/p&gt;

&lt;p&gt;The practical test is to sit a new developer in front of the docs and ask whether they can complete a real authenticated, multi-step workflow without opening another tool. If they can only read the shape and then leave to build the request elsewhere, the documentation is a glossary rather than a guide. Keep the polished static reference, but make sure the playground genuinely authenticates, preserves state, and returns the real errors that the gateway produces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is a rendered static API reference enough?
&lt;/h3&gt;

&lt;p&gt;It answers what fields exist and how the schema is shaped, but it cannot verify auth, show a real error, or walk a multi-step flow. Those need an interactive playground.&lt;/p&gt;

&lt;h3&gt;
  
  
  What makes a playground truly interactive?
&lt;/h3&gt;

&lt;p&gt;Real environment selection, authentication through the declared scheme, live responses and errors, and the ability to capture a value from one response and use it in the next request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do many playgrounds feel useless?
&lt;/h3&gt;

&lt;p&gt;They send a single request against a hardcoded demo host with a shared token and cannot chain calls or preserve state, so they do not model a real integration workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should the playground use a separate demo token?
&lt;/h3&gt;

&lt;p&gt;Prefer the declared security scheme with the developer's own credentials against staging. A shared demo token hides the auth and gateway behavior the docs are meant to teach.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do reference and playground stay consistent?
&lt;/h3&gt;

&lt;p&gt;Generate both from the same OpenAPI contract, so the rendered schema, environments, auth, and examples share one source and cannot drift into separate artifacts.&lt;/p&gt;

&lt;p&gt;This is part of the &lt;a href="https://www.powerduck.com/blog/powerduck-vs-mintlify/" rel="noopener noreferrer"&gt;Powerduck vs Mintlify&lt;/a&gt; comparison — start there for the full picture of useful developer documentation.&lt;/p&gt;

</description>
      <category>openapi</category>
      <category>documentation</category>
      <category>developers</category>
    </item>
    <item>
      <title>I built a fake courtroom for life's pettiest arguments</title>
      <dc:creator>DaKaufeeBoii</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:38:50 +0000</pubDate>
      <link>https://dev.to/dakaufeeboii/i-built-a-fake-courtroom-for-lifes-pettiest-arguments-2ejf</link>
      <guid>https://dev.to/dakaufeeboii/i-built-a-fake-courtroom-for-lifes-pettiest-arguments-2ejf</guid>
      <description>&lt;p&gt;Look, we've all been there.&lt;/p&gt;

&lt;p&gt;Someone leaves two seconds on the microwave and doesn't hit clear.&lt;br&gt;&lt;br&gt;
Someone eats the last slice of cold pizza with your name on the box.&lt;br&gt;&lt;br&gt;
Someone steals the blanket at 3 AM and rolls themselves into a human burrito.&lt;/p&gt;

&lt;p&gt;In the real world, the cops won't help you and no real court cares. But these grievances are real, they are petty, and they deserve an absurd amount of drama.&lt;/p&gt;

&lt;p&gt;So over the weekend, I built &lt;strong&gt;&lt;a href="https://petty-court.replit.app" rel="noopener noreferrer"&gt;Petty Court: The Court of Very Small Claims&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its motto: &lt;em&gt;“Lex Minima · Est. Five Minutes Ago.”&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Its presiding judge: &lt;em&gt;The Honorable Reginald P. Pettiness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's how it works and how I built it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The concept: Commit to the bit
&lt;/h2&gt;

&lt;p&gt;Most hackathon or side-project AI apps make the same mistake: it's just a blank text box, a dark-mode card, and a generic button that spits out a paragraph of ChatGPT text.&lt;/p&gt;

&lt;p&gt;That gets old in 10 seconds. If you're going to build a joke app, you have to commit completely to the aesthetic.&lt;/p&gt;

&lt;p&gt;So instead of a form, I built an entire illustrated courthouse floor plan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Entrance&lt;/strong&gt;: You push through saloon-style double doors that swing open into the courtroom, complete with wooden gavel sound effects and live docket counters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Courtroom No. 1&lt;/strong&gt;: An interactive illustration where you click on physical spots in the room—the Clerk's Desk, the Bench, the Jury Gallery, or the Records Room.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form PC-01&lt;/strong&gt;: An official petition filed in duplicate. You can type your own dispute or pick from classic precedents like &lt;em&gt;The Great Sock Disappearance Ordinance of 1986&lt;/em&gt; or &lt;em&gt;The Doctrine of Implied Pizza Crust Ownership&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;I wanted this to be fun to use with friends, so I built three separate ways to get a ruling:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Classic Court (Instant chaos)
&lt;/h3&gt;

&lt;p&gt;If you just want an immediate ruling in 1.2 seconds, Judge Reginald picks from a pool of satirical laws, creates formal "Findings of Fact" (&lt;em&gt;"The defense's central theory appears to be 'it seemed fine at the time,' which is not a recognized unit of measurement"&lt;/em&gt;), stamps a giant red GUILTY on the screen, and hands down a petty sentence like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Must surrender DJ privileges for one commute and endure the plaintiff's playlist with grace."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And if you don't like it? There's an &lt;strong&gt;Appeal&lt;/strong&gt; button that appeals right back to the exact same judge.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. The AI Judge (BYOK)
&lt;/h3&gt;

&lt;p&gt;If you want a real custom ruling on a weird argument, you can summon the digital magistrate.&lt;/p&gt;

&lt;p&gt;Instead of burning my own API keys or setting up a fragile backend proxy, I used a &lt;strong&gt;BYOK (Bring Your Own Key)&lt;/strong&gt; model. You paste in your OpenAI key, and the client sends your dispute and arguments directly with a strict prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Judge Reginald's brain in a nutshell&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
You are Judge Reginald P. Pettiness, presiding over the Court of Very Small Claims. 
The case involves an extremely minor domestic grievance.
Treat this matter with unwarranted Victorian judicial gravity.
Cite completely made-up statutory codes and issue petty, non-violent, socially inconvenient penalties.
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app parses the response into formal docket fields: Charge, Findings of Fact, Sentence, and Final Word.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. People's Court (Live multiplayer)
&lt;/h3&gt;

&lt;p&gt;This is where it gets fun. You can open a room, get a 6-character room code (like &lt;code&gt;BA7AE7&lt;/code&gt;), and send the link to a group chat.&lt;/p&gt;

&lt;p&gt;Everyone picks a role:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Judge&lt;/strong&gt; (controls the courtroom, gavels people down, issues rulings)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plaintiff &amp;amp; Defendant&lt;/strong&gt; (file their claims and defense statements)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Witness&lt;/strong&gt; (takes the stand, answers direct cross-examination questions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jury&lt;/strong&gt; (votes on who is actually in the wrong)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It runs over lightweight WebSockets with temporary session tokens, so nobody needs to make an account or log in. You just click, type a name, and start arguing.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Zero-database records room
&lt;/h3&gt;

&lt;p&gt;I didn't want a heavy database or user accounts for something that's supposed to be lighthearted.&lt;/p&gt;

&lt;p&gt;Your case history lives right in your browser's local storage in the &lt;strong&gt;Records Room&lt;/strong&gt;. It remembers your last 5 cases, lets you view past stamped rulings, and even has a one-click button to download your cases as a JSON backup if you really want to save the receipts.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned building this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Micro-copy does 80% of the heavy lifting&lt;/strong&gt;: The difference between an app feeling generic and feeling memorable is the copy. Writing things like &lt;em&gt;"Petitions accepted, however small"&lt;/em&gt; or &lt;em&gt;"An appeal goes before the very same judge; he has promised to consider it with an entirely open mind"&lt;/em&gt; makes people laugh before they even use the core feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio adds instant personality&lt;/strong&gt;: Adding a subtle toggle for gavel thuds and courtroom chatter makes the UI feel like a video game rather than a website.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the friction at zero&lt;/strong&gt;: No signups, no email verification, no complex onboarding. Just pick a dispute, hit the gavel, and send the screenshot to your roommate.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Give it a spin
&lt;/h2&gt;

&lt;p&gt;If someone in your house is currently committing domestic crimes against snack etiquette or the thermostat, take them to court:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://petty-court.replit.app" rel="noopener noreferrer"&gt;The Game&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://medium.com/@saitarunrdy/building-petty-court-why-i-built-an-illustrated-courtroom-for-lifes-most-microscopic-injustices-9fb74698651c?sharedUserId=saitarunrdy" rel="noopener noreferrer"&gt;Medium Post&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://lnkd.in/p/dKyN5SGT" rel="noopener noreferrer"&gt;LinkedIn Post&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Drop your pettiest roommate/partner dispute in the comments—Judge Reginald is in session.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Humanize OpenRouter Output in Java: A Zero-Dependency Linter for Bold-Label Bullets, Emoji and Title Case + 5 Free Tools (2026)</title>
      <dc:creator>UnAIMyText</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:37:55 +0000</pubDate>
      <link>https://dev.to/unaimytext_app/humanize-openrouter-output-in-java-a-zero-dependency-linter-for-bold-label-bullets-emoji-and-1b71</link>
      <guid>https://dev.to/unaimytext_app/humanize-openrouter-output-in-java-a-zero-dependency-linter-for-bold-label-bullets-emoji-and-1b71</guid>
      <description>&lt;p&gt;&lt;em&gt;Last verified November 2026. Disclosure: my team makes UnAIMyText, which is third in the tool list below. The Java is free to copy.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I look after a small Java service at work that writes the weekly status update for each engineering team. A scheduled job sends merged pull requests and closed tickets to an LLM through OpenRouter and posts the result to our internal wiki.&lt;/p&gt;

&lt;p&gt;The updates were accurate, and they all looked like the same slide deck: bold-label bullets, Title Case headings, a rocket in front of half of them. Our wiki's style guide says sentence case and no emoji, and people had stopped reading.&lt;/p&gt;

&lt;p&gt;So I wrote a linter. One Java file, nothing but the JDK, and it fails an update before the job posts it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the linter checks
&lt;/h2&gt;

&lt;p&gt;My earlier checkers in this series looked at wording and punctuation. This one looks at Markdown structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bold-label bullets.&lt;/strong&gt; &lt;code&gt;- **Faster Builds:** CI now caches...&lt;/code&gt; once is fine. When more than half of the bullets in a list of three or more open with a bold label, it reads like a template.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emoji.&lt;/strong&gt; More than one emoji fails. The count skips fenced code and inline code, so a deploy script that prints a rocket doesn't count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Title Case headings.&lt;/strong&gt; A heading of three or more words where the words after the first are capitalized (ignoring small words like "and" or "for", and acronyms like API) is Title Case. More than one fails, because our house style is sentence case.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The exit code is 0 for a pass, 1 for a rewrite and 2 when the API call fails. &lt;code&gt;--json&lt;/code&gt; prints a machine-readable report.&lt;/p&gt;

&lt;h2&gt;
  
  
  The request
&lt;/h2&gt;

&lt;p&gt;OpenRouter's &lt;a href="https://openrouter.ai/docs/api_reference/overview" rel="noopener noreferrer"&gt;API reference&lt;/a&gt; describes &lt;code&gt;POST /api/v1/chat/completions&lt;/code&gt; with an OpenAI-style body and a bearer token. A few details from it shaped the code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;HTTP-Referer&lt;/code&gt; and &lt;code&gt;X-OpenRouter-Title&lt;/code&gt; are optional headers that identify your app (&lt;code&gt;X-Title&lt;/code&gt; is also accepted). The linter only sends them if you set &lt;code&gt;OPENROUTER_APP_URL&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;finish_reason&lt;/code&gt; is normalized to &lt;code&gt;tool_calls&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;length&lt;/code&gt;, &lt;code&gt;content_filter&lt;/code&gt; or &lt;code&gt;error&lt;/code&gt;. Anything other than &lt;code&gt;stop&lt;/code&gt; prints a warning to stderr, so a truncated update doesn't get posted quietly.&lt;/li&gt;
&lt;li&gt;A choice can carry its own &lt;code&gt;error&lt;/code&gt; object, and &lt;code&gt;message.content&lt;/code&gt; can be null. Both count as a failed request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The default model is &lt;code&gt;openai/gpt-oss-20b&lt;/code&gt;, which is a reasoning model. OpenRouter's &lt;a href="https://openrouter.ai/docs/guides/best-practices/reasoning-tokens" rel="noopener noreferrer"&gt;reasoning tokens guide&lt;/a&gt; says that on Chat Completions, reasoning appears in a &lt;code&gt;reasoning&lt;/code&gt; field on each message, and that &lt;code&gt;reasoning.exclude&lt;/code&gt; omits it from the response (the tokens are still billed). The request sets &lt;code&gt;"reasoning": {"exclude": true}&lt;/code&gt;, and the linter reads only &lt;code&gt;message.content&lt;/code&gt; either way, because that's what gets posted.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OPENROUTER_MODEL&lt;/code&gt; switches models and &lt;code&gt;OPENROUTER_BASE_URL&lt;/code&gt; points the linter at a mock.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Java 17 or newer. Run it straight from source with &lt;code&gt;java StatusLint.java&lt;/code&gt;; there's no build step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.net.URI&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.net.http.HttpClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.net.http.HttpRequest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.net.http.HttpResponse&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.nio.charset.StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.Duration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.LinkedHashMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.regex.Pattern&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/** Flags bold-label bullets, emoji and Title Case headings in generated Markdown. */&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StatusLint&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// House style knobs.&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;MIN_BULLETS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="no"&gt;MAX_BOLD_SHARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;MAX_EMOJI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;MAX_TITLE_CASE_HEADINGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="no"&gt;FENCE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"(?ms)^```

.*?^

```[ \\t]*$"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="no"&gt;HEADING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^\\s{0,3}#{1,6}\\s+(.+?)\\s*#*\\s*$"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="no"&gt;BULLET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^\\s*(?:[-*+]|\\d+[.)])\\s+(.*)$"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="no"&gt;BOLD_LABEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^(?:\\*\\*|__)[^*_]{1,40}(?::(?:\\*\\*|__)|(?:\\*\\*|__):)"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="no"&gt;SMALL_WORDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"a|an|and|as|at|but|by|for|in|nor|of|on|or|the|to|vs|via|with"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;bullets&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;boldBullets&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;emoji&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;headings&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;titleCaseHeadings&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;markdown&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FENCE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;markdown&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;replaceAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;bullets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;titleCase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\R"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;HEADING&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;headings&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isTitleCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="n"&gt;titleCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BULLET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;bullets&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;BOLD_LABEL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="n"&gt;bold&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;noInlineCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"`[^`\\n]*`"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;emoji&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;noInlineCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;codePoints&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;StatusLint:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;isEmoji&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reasons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bullets&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="no"&gt;MIN_BULLETS&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;bold&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bullets&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;MAX_BOLD_SHARE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bold-label bullets"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emoji&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MAX_EMOJI&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"emoji"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;titleCase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MAX_TITLE_CASE_HEADINGS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Title Case headings"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bullets&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bold&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;emoji&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headings&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;titleCase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/** Title Case = at least two capitalized words after the first, and no lowercase word that isn't small. */&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isTitleCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;heading&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;heading&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[^\\p{L}\\p{N}'\\s-]"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\s+"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;capped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nc"&gt;Character&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isLetter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Character&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isUpperCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="n"&gt;capped&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt; &lt;span class="c1"&gt;// skip acronyms like API&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="no"&gt;SMALL_WORDS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;capped&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isEmoji&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x1F300&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mh"&gt;0x1FAFF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x2600&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mh"&gt;0x27BF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x1F1E6&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mh"&gt;0x1F1FF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mh"&gt;0x2B50&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mh"&gt;0x2705&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;askOpenRouter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getenv&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getOrDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OPENROUTER_BASE_URL"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://openrouter.ai/api/v1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getenv&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getOrDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OPENROUTER_MODEL"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"openai/gpt-oss-20b"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{\"model\":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;",\"messages\":[{\"role\":\"user\",\"content\":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"}]"&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;",\"reasoning\":{\"exclude\":true}}"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// keep thinking out of the reply&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/+$"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/chat/completions"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;appUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getenv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OPENROUTER_APP_URL"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// optional attribution&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appUrl&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HTTP-Referer"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;appUrl&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"X-OpenRouter-Title"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"statuslint"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;connectTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyPublishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTF_8&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HTTP "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;": "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;snippet&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;choices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; &lt;span class="s"&gt;"choices"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"no choices in reply"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;choice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"provider error: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"finish_reason"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="s"&gt;"stop"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"warning: finish_reason="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Only message.content is checked; a "reasoning" field, if any, is ignored.&lt;/span&gt;
        &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;String&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="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"reply had no content"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;asJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--json"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getenv&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getOrDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OPENROUTER_API_KEY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readAllBytes&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTF_8&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;askOpenRouter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"request failed: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asJson&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bullets"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bullets&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"bold_bullets"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;boldBullets&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                    &lt;span class="s"&gt;"emoji"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emoji&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"headings"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headings&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                    &lt;span class="s"&gt;"title_case_headings"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;titleCaseHeadings&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"reasons"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;())));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bullets: %d (%d bold-label), emoji: %d, headings: %d (%d Title Case)%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bullets&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;boldBullets&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emoji&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headings&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;titleCaseHeadings&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"verdict: ok"&lt;/span&gt;
                    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"verdict: rewrite ("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"; "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;")"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reasons&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/** Just enough JSON for one request and one response; no dependencies. */&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;s&lt;/span&gt; &lt;span class="o"&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="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Json&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;i&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"trailing data at "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IndexOutOfBoundsException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"truncated JSON"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,&lt;/span&gt; &lt;span class="o"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toCharArray&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'"'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\\""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'\\'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\\\"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\n"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'\r'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\r"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'\t'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\t"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mh"&gt;0x20&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\u%04x"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'"'&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,&lt;/span&gt; &lt;span class="o"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TreeMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"{"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"["&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Json:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"]"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Character&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isWhitespace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unexpected end of JSON"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'{'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'['&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'"'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TRUE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FALSE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"null"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s"&gt;"+-0123456789.eE"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;indexOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bad JSON at "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LinkedHashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'}'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;':'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'}'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;']'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;']'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'"'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sc"&gt;'"'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++);&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++);&lt;/span&gt;
                &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'n'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'t'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\t'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'r'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\r'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'b'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\b'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'f'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\f'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="sc"&gt;'u'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// \" \\ \/&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" at "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why a hand-rolled JSON reader?&lt;/strong&gt; I wanted a single file that runs on a bare JDK. The &lt;code&gt;Json&lt;/code&gt; class handles exactly one request and one response shape; for anything bigger, use Jackson.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emoji detection is approximate.&lt;/strong&gt; It counts code points in the main emoji blocks. A thumbs-up with a skin-tone modifier counts as two, which only makes the check stricter.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A mock OpenRouter server
&lt;/h2&gt;

&lt;p&gt;The JDK ships a small HTTP server in &lt;code&gt;com.sun.net.httpserver&lt;/code&gt;, which is enough for tests. Every mode puts emoji-heavy bait in a &lt;code&gt;reasoning&lt;/code&gt; field that the linter must ignore, and the log shows whether &lt;code&gt;reasoning.exclude&lt;/code&gt; and the attribution header were sent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.sun.net.httpserver.HttpServer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.net.InetSocketAddress&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.nio.charset.StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/** java MockOpenRouter.java 8091 robotic|clean|length */&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MockOpenRouter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"8091"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"robotic"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"length"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"length"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"stop"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"robotic"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"## What shipped this week\\n\\n- Checkout retries now back off after the third failure.\\n"&lt;/span&gt;
                  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"- The refunds report loads in about two seconds instead of nine.\\n"&lt;/span&gt;
                  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"- Priya fixed the timezone bug in the invoice footer.\\n\\n## Next week\\n\\nWe start on saved cards."&lt;/span&gt;
                &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"## \uD83D\uDE80 Weekly Status Update for the Payments Team\\n\\n"&lt;/span&gt;
                  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"- **Faster Checkout:** Retries are now smarter \u2705\\n"&lt;/span&gt;
                  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"- **Better Reports:** Refunds load in record time \uD83D\uDD25\\n"&lt;/span&gt;
                  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"- **Bug Fixes:** Invoice footers are fixed\\n\\n## Looking Ahead to Next Week\\n\\nSaved cards are next! \uD83C\uDF89"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;bait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"## Internal Reasoning Notes Here\\n- **Plan:** add emoji \uD83D\uDE80\uD83D\uDE80\uD83D\uDE80"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="nc"&gt;HttpServer&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InetSocketAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestBody&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;readAllBytes&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTF_8&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mock got "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestMethod&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestURI&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getPath&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" exclude="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\"exclude\":true"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" referer="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestHeaders&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HTTP-Referer"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestURI&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getPath&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/chat/completions"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{\"error\":{\"code\":404,\"message\":\"not found\"}}"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{\"id\":\"gen-mock\",\"object\":\"chat.completion\",\"model\":\"openai/gpt-oss-20b\","&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\"choices\":[{\"finish_reason\":\""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\",\"native_finish_reason\":\""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\","&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\"message\":{\"role\":\"assistant\",\"content\":\""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\",\"reasoning\":\""&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bait&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\"}}]}"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTF_8&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResponseHeaders&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendResponseHeaders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResponseBody&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mock listening on "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;")"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;javac &lt;span class="nt"&gt;-Xlint&lt;/span&gt;:all &lt;span class="nt"&gt;-Werror&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; /tmp/build StatusLint.java MockOpenRouter.java

&lt;span class="c"&gt;# lint an exported update&lt;/span&gt;
java StatusLint.java &amp;lt; updates/platform-team.md

&lt;span class="c"&gt;# generate with OpenRouter, then lint&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENROUTER_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
java StatusLint.java &lt;span class="s2"&gt;"Write this week's status update from these merged PRs: ..."&lt;/span&gt;

&lt;span class="c"&gt;# point at the mock&lt;/span&gt;
java MockOpenRouter.java 8091 robotic &amp;amp;
&lt;span class="nv"&gt;OPENROUTER_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test &lt;/span&gt;&lt;span class="nv"&gt;OPENROUTER_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://127.0.0.1:8091 java StatusLint.java &lt;span class="s2"&gt;"anything"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test results
&lt;/h2&gt;

&lt;p&gt;Both files compiled with &lt;code&gt;javac -Xlint:all -Werror&lt;/code&gt; and no warnings. I ran the same test script on OpenJDK 21.0.10 and 17.0.18, and the output matched line for line.&lt;/p&gt;

&lt;p&gt;A sprint update in the robotic style had four bullets (three with bold labels), four emoji and three Title Case headings, and exited 1. A one-line note with two emoji exited 1 on emoji alone. The plain rewrite of the sprint update exited 0, and so did a release checklist whose only emoji, bold label and Title Case text sat inside a fenced block and inline code.&lt;/p&gt;

&lt;p&gt;The mock's robotic reply tripped every check. Its clean mode exited 0 even though its &lt;code&gt;reasoning&lt;/code&gt; field was full of rockets, and the mock log confirmed &lt;code&gt;"exclude":true&lt;/code&gt; in every request and the &lt;code&gt;HTTP-Referer&lt;/code&gt; header only when &lt;code&gt;OPENROUTER_APP_URL&lt;/code&gt; was set. The &lt;code&gt;length&lt;/code&gt; mode printed &lt;code&gt;warning: finish_reason=length&lt;/code&gt; and still produced a report. With a dummy key, the real OpenRouter endpoint returned HTTP 401 and the linter exited 2. Pointing it at a closed port produced a &lt;code&gt;ConnectException&lt;/code&gt; and the same exit code. I didn't spend credits on a live completion.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 free tools for fixing a failed update
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. markdownlint
&lt;/h3&gt;

&lt;p&gt;markdownlint checks Markdown files against a set of structural rules and runs in editors and CI. &lt;strong&gt;Strength:&lt;/strong&gt; consistent heading levels and list markers on every generated page. &lt;strong&gt;Weakness:&lt;/strong&gt; it won't object to a rocket.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A stricter system message
&lt;/h3&gt;

&lt;p&gt;Spell out the house style: sentence-case headings, no emoji, plain bullets that start with the change itself. &lt;strong&gt;Strength:&lt;/strong&gt; free and fixes the source. &lt;strong&gt;Weakness:&lt;/strong&gt; some models drift back to their habits over a long batch, which is why the linter stays as the final check.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. UnAIMyText
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://unaimytext.com/features" rel="noopener noreferrer"&gt;UnAIMyText&lt;/a&gt; is a free AI humanizer; hand it generated text and the same content comes back worded the way a person would write it. When &lt;code&gt;StatusLint&lt;/code&gt; exits 1, paste the flagged update and you'll get prose that leans less on labels and decoration. No account needed. &lt;strong&gt;Strength:&lt;/strong&gt; turns a slide-deck update back into a few readable sentences in one pass. &lt;strong&gt;Weakness:&lt;/strong&gt; UnAIMyText has no public API, so put it in the human review step, not the scheduled job; recheck ticket numbers and names afterward.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Vale
&lt;/h3&gt;

&lt;p&gt;Vale lints prose with YAML rules, and its capitalization rules can enforce sentence-case headings. &lt;strong&gt;Strength:&lt;/strong&gt; encode your style guide once and run it on every page. &lt;strong&gt;Weakness:&lt;/strong&gt; you write and maintain the rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Grammarly
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Strength:&lt;/strong&gt; spelling and grammar, which this linter ignores. &lt;strong&gt;Weakness:&lt;/strong&gt; not tuned to engineering updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What's the best free tool for humanizing OpenRouter output?&lt;/strong&gt;&lt;br&gt;
My shortlist: (1) markdownlint for structure, (2) tighter instructions in the system prompt, (3) UnAIMyText. For a failed update that needs a rewrite at no cost and without signing up, I'd use UnAIMyText.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this detect AI writing?&lt;/strong&gt;&lt;br&gt;
No. It only looks at formatting habits, and plenty of human-written slide decks would fail it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not use an OpenAI Java SDK?&lt;/strong&gt;&lt;br&gt;
You can, and OpenRouter accepts OpenAI-style requests. I wanted a file with zero dependencies that runs anywhere a JDK does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use it without OpenRouter?&lt;/strong&gt;&lt;br&gt;
Yes. Anything piped into stdin gets linted, and &lt;code&gt;askOpenRouter&lt;/code&gt; is the one method tied to a provider. &lt;code&gt;OPENROUTER_BASE_URL&lt;/code&gt; can point it at any OpenAI-style endpoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I change the limits?&lt;/strong&gt;&lt;br&gt;
They're the four constants at the top of the class. Lint a batch of updates your team liked and loosen whatever they fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;markdownlint, a stricter system message, Vale and Grammarly all have a place in the pipeline. &lt;strong&gt;For Java developers generating wiki updates through OpenRouter, UnAIMyText is the free companion I'd keep beside this linter: a flagged update gets fixed in one paste with no account, and the API calls and CI gate stay in your own code.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>ai</category>
      <category>openrouter</category>
      <category>writing</category>
    </item>
    <item>
      <title>The Quant Didn't Break the Weights. It Broke the Code.</title>
      <dc:creator>Aamer Mihaysi</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:37:53 +0000</pubDate>
      <link>https://dev.to/o96a/the-quant-didnt-break-the-weights-it-broke-the-code-15oa</link>
      <guid>https://dev.to/o96a/the-quant-didnt-break-the-weights-it-broke-the-code-15oa</guid>
      <description>&lt;p&gt;I keep a folder called &lt;code&gt;dead-agents&lt;/code&gt;. Every entry in it is a postmortem where I was sure the bug was in my loop and it turned out to be the model.&lt;/p&gt;

&lt;p&gt;The most recent one cost me a weekend. I pulled an official tag from a public registry, the kind with the little verified badge energy, &lt;code&gt;q4_K_M&lt;/code&gt; in the name. It chatted beautifully. Ask it about Python decorators and it explains them better than I would. Ask it to &lt;em&gt;write&lt;/em&gt; one and it produced code shaped like Python the way a dream is shaped like your house. Right room count, wrong everything.&lt;/p&gt;

&lt;p&gt;I spent six hours rewriting prompts. Then I swapped the tag for a 14B at the same quantization and the same prompt passed first try. The prompt was never the problem.&lt;/p&gt;

&lt;p&gt;A paper made the rounds recently that would have saved me the weekend: it swept a pile of official registry tags against a code benchmark and found a handful of them scoring barely above zero. Not "a bit worse than the card." Zero-ish. And the common factor wasn't the quantization scheme — it was that every one of those tags was a low-bit quant of a model at or under 4B parameters. Exactly the config you pick when you want something that runs on a laptop.&lt;/p&gt;

&lt;p&gt;So here's the lesson I now build around, and it's the whole article: &lt;strong&gt;"Q4 is basically lossless" is not a property of quantization. It's a property of model size.&lt;/strong&gt; At 70B, four bits costs you noise. At 3B, four bits costs you the thing.&lt;/p&gt;

&lt;p&gt;Mini-lesson follows. Fifteen minutes of setup, and you never get ambushed by this again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Know what you actually downloaded
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ollama show &amp;lt;tag&amp;gt;&lt;/code&gt; gives you parameter count, quantization, context length. Read it. Two things bite here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tags move.&lt;/strong&gt; A publisher repushes under the same tag and your digest changes silently. Run &lt;code&gt;ollama list&lt;/code&gt; and pin the ID next to the tag in your config, your compose file, your Dockerfile, wherever. If the ID changes, you want to know about it in CI, not in production at 2am.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The family name tells you nothing about size.&lt;/strong&gt; &lt;code&gt;some-model:q4_K_M&lt;/code&gt; and &lt;code&gt;some-model:70b-q4_K_M&lt;/code&gt; look like siblings. They are not. One is a demo, the other is a tool.&lt;/p&gt;

&lt;p&gt;Write the digest and the parameter count down in the same place you write down the pass rate from step 3. That file becomes the most honest model card you own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Build a smoke test you'll actually run
&lt;/h2&gt;

&lt;p&gt;Not a benchmark suite. Twenty problems, each with a signature, a short docstring, and two or three asserts. You grade it by counting booleans. No LLM judge — a judge at temperature 0 is a second unreliable system grading the first, and now you have two things to debug.&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="c1"&gt;# smoke.py — deterministic, no judge, 20 cases
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;textwrap&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;

&lt;span class="n"&gt;CASES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a Python function parse_kv(s) that turns &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                  &lt;span class="sh"&gt;"'&lt;/span&gt;&lt;span class="s"&gt;a=1,b=2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; into {&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;}. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Return only the function.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tests&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;
assert parse_kv(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a=1,b=2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;) == {&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;}
assert parse_kv(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="s"&gt;) == {}
assert parse_kv(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a=1,a=2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;) == {&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;}
&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;# ... 19 more, same shape
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;```

&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
    &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;

```&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;passes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num_predict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tests&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                       &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;passes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;CASES&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CASES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;timeout=5&lt;/code&gt; is not paranoia. A degraded quant will cheerfully write you a &lt;code&gt;while True&lt;/code&gt; that looks like a solution and never returns.&lt;/p&gt;

&lt;p&gt;Twenty cases is enough to separate 2/20 from 16/20, and small enough that you'll run it. That last part is the only part that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Run the control, because the number alone means nothing
&lt;/h2&gt;

&lt;p&gt;A score with no comparison is a feeling with a decimal point. Run the same script against three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the artifact you actually downloaded,&lt;/li&gt;
&lt;li&gt;the biggest model you can afford at the same quant,&lt;/li&gt;
&lt;li&gt;ideally, the unquantized version of the same base model if it exists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's how you tell "this model can't code" apart from "this quant can't code." On my box, a 3B at Q4 scored 3/20. A 14B at the same Q4 scored 16/20. A 7B at Q8 landed around 11/20. Size beat bits, twice, on the same afternoon. I've stopped being surprised by that and started budgeting RAM for it instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Test the thing your agent actually needs
&lt;/h2&gt;

&lt;p&gt;Code generation is the visible failure. Structured output is the silent one, and it's the one that kills agents.&lt;/p&gt;

&lt;p&gt;Take ten prompts, require JSON with specific keys, parse it. Count three things separately: unparseable, parseable but missing keys, and correct. A model that returns &lt;code&gt;{}&lt;/code&gt; parses fine and does nothing, which is worse than a crash because your loop keeps going. Do the same with your actual tool-call schema. Ten calls, count the valid ones. If it's not 10/10 on a schema that simple, it's not a planner, whatever the card says.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Set a floor, not a vibe
&lt;/h2&gt;

&lt;p&gt;Mine, roughly: under 12/20 on the code smoke test never touches a repository. Under 9/10 on structured output never gets to be an agent's planner. Below both, the model can classify, summarize, route, or draft — and that's a real job. It just isn't the job people buy the laptop for.&lt;/p&gt;

&lt;p&gt;Put the numbers in CI. Tags move. Digests don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I do when it fails
&lt;/h2&gt;

&lt;p&gt;Go up in parameters before you go up in bits. Every time I've measured it, a bigger base model at Q4 has beaten a smaller one at Q8 on the same hardware, and it costs about the same in RAM. If the RAM isn't there, then you don't have a code model — you have a chatbot that can also write prose about code, which is fine, but label it that way in your README.&lt;/p&gt;

&lt;p&gt;And be honest about the registry problem underneath all this. An official tag means a publisher uploaded it. It doesn't mean anyone ran a single test on the 1.5B quant before it went public. Assume nobody did, yourself included, and let the twenty-case script be the check that nobody else ran.&lt;/p&gt;

&lt;p&gt;Mine now runs before the agent starts. Three minutes, no GPU drama, and it has already caught two regressions I would have blamed on my own prompt engineering. Worth it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
