<?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: Iurii Panarin</title>
    <description>The latest articles on DEV Community by Iurii Panarin (@pxyup).</description>
    <link>https://dev.to/pxyup</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F109451%2F3af66a72-67bb-4e9b-9f6d-af1123785aaa.jpeg</url>
      <title>DEV Community: Iurii Panarin</title>
      <link>https://dev.to/pxyup</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pxyup"/>
    <language>en</language>
    <item>
      <title>Your LLM can scrape the web — locally, without writing throwaway code</title>
      <dc:creator>Iurii Panarin</dc:creator>
      <pubDate>Thu, 23 Jul 2026 18:49:12 +0000</pubDate>
      <link>https://dev.to/pxyup/your-llm-can-scrape-the-web-locally-without-writing-throwaway-code-3lj</link>
      <guid>https://dev.to/pxyup/your-llm-can-scrape-the-web-locally-without-writing-throwaway-code-3lj</guid>
      <description>&lt;p&gt;Every time you ask an AI assistant to "get data from this website", one of two things happens: it hallucinates the data, or it writes a one-off Python script you'll never run again. Both are wasteful. The model already knows &lt;em&gt;where&lt;/em&gt; the data lives and &lt;em&gt;how&lt;/em&gt; to select it — what's missing is a safe, reusable way to execute that knowledge.&lt;/p&gt;

&lt;p&gt;That's what &lt;a href="https://github.com/PxyUp/fitter" rel="noopener noreferrer"&gt;fitter&lt;/a&gt; does. It's a small Go engine with one idea at its core: &lt;strong&gt;web extraction should be a config, not code&lt;/strong&gt;. A fitter config declares where the data lives (HTTP request, headless browser, static value, file) and what to extract (gjson paths, CSS selectors, XPath). The engine does the rest.&lt;/p&gt;

&lt;p&gt;And because configs are plain JSON/YAML, &lt;strong&gt;an LLM can author them&lt;/strong&gt;. Fitter ships an &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;MCP&lt;/a&gt; server, so Claude Code, Claude Desktop, or any MCP client can write a config, validate it, and run it on your machine — in one conversation turn.&lt;/p&gt;

&lt;h2&gt;
  
  
  60-second setup
&lt;/h2&gt;

&lt;p&gt;Grab a binary from the &lt;a href="https://github.com/PxyUp/fitter/releases" rel="noopener noreferrer"&gt;releases page&lt;/a&gt; (or &lt;code&gt;go build -o fitter_mcp ./cmd/mcp&lt;/code&gt;), then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add fitter &lt;span class="nt"&gt;-s&lt;/span&gt; user &lt;span class="nt"&gt;--&lt;/span&gt; /path/to/fitter_mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Desktop users: download the &lt;code&gt;.mcpb&lt;/code&gt; bundle for your platform from the same release page and open it — that's the whole install.&lt;/p&gt;

&lt;p&gt;The server exposes five tools: &lt;code&gt;fitter_run&lt;/code&gt;, &lt;code&gt;fitter_run_file&lt;/code&gt;, &lt;code&gt;fitter_run_url&lt;/code&gt;, &lt;code&gt;fitter_validate_config&lt;/code&gt;, and &lt;code&gt;fitter_config_reference&lt;/code&gt; — that last one returns a condensed format reference, so the model can teach itself the config format without leaving the conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Get me the latest Hacker News stories"
&lt;/h2&gt;

&lt;p&gt;Ask exactly that. Behind the scenes, the model authors something like this and calls &lt;code&gt;fitter_run&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://hacker-news.firebaseio.com/v0/newstories.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"server_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"array_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"root_path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@this"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"length_limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"item_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"generated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://hacker-news.firebaseio.com/v0/item/{PL}.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"server_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"object_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"by"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"by"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"int"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"score"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"limits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"host_request_limiter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hacker-news.firebaseio.com"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read it top to bottom: fetch the ID list, take the first 10, and for &lt;strong&gt;each element&lt;/strong&gt; fire a nested request (&lt;code&gt;{PL}&lt;/code&gt; is the current value) to fetch the story object — rate-limited to 5 parallel requests against the HN API. The result is clean JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fields Medals 2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"by"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nill0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.mathunion.org/..."&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Writing by Hand is Good for your Brain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"by"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dwwoelfel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the part that matters: &lt;strong&gt;that config is an artifact, not an afterthought&lt;/strong&gt;. Save it to a file and it's a CLI command, a cron job, or a service — the model's one-off answer became infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  One config, four data sources
&lt;/h2&gt;

&lt;p&gt;My actual morning briefing — weather, HN, world headlines, and the Bitcoin price — is &lt;a href="https://github.com/PxyUp/fitter/blob/master/examples/config_morning_briefing.json" rel="noopener noreferrer"&gt;one config&lt;/a&gt; with four independent branches. It also shows off placeholders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://wttr.in/{{{FromInput=.}}}?format=j1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;{{{FromInput=.}}}&lt;/code&gt; is filled from the tool's &lt;code&gt;input&lt;/code&gt; argument at run time, so &lt;em&gt;"run my briefing for Berlin"&lt;/em&gt; and &lt;em&gt;"for Paris"&lt;/em&gt; reuse the same config. There are placeholders for env vars, cached references (think: fetch a JWT once, use it in every request's headers), array indices, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join sources: scrape what has no API, enrich from the one that does
&lt;/h2&gt;

&lt;p&gt;GitHub's trending page famously has &lt;strong&gt;no API&lt;/strong&gt;. But the repos on it do. So: scrape the HTML for the repo slugs, then fan each one out into the real GitHub REST API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTML"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/trending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"server_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"User-Agent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mozilla/5.0 (fitter demo)"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"array_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"root_path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"article.Box-row h2 a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"length_limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"item_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"html_attribute"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"generated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.github.com/repos{PL}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"server_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"User-Agent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fitter-demo"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"null_on_error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"object_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"full_name"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"stars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"int"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stargazers_count"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"open_issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"int"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"open_issues_count"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"description"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"limits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"host_request_limiter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"api.github.com"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Today's actual output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"block/buzz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"stars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6214&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rust"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"open_issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;460&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A hive mind communication platform"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"koala73/worldmonitor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"stars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;71179&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TypeScript"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"open_issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;272&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Real-time global intelligence dashboard. AI-powered news aggregation..."&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shiyu-coder/Kronos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"stars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32946&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"open_issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;241&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Kronos: A Foundation Model for the Language of Financial Markets"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pumpkin-MC/Pumpkin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"stars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8808&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rust"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"open_issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;207&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Empowering everyone to host fast and efficient Minecraft servers."&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"citrolabs/ego-lite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"stars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1485&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JavaScript"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"open_issues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The best browser for both you and your AI agents work in parallel."&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The details worth stealing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML and JSON mix freely.&lt;/strong&gt; The outer connector parses HTML with a CSS selector (&lt;code&gt;article.Box-row h2 a&lt;/code&gt;); each matched element fans out into a JSON API request. One config, two worlds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;html_attribute&lt;/code&gt; reads attributes, not text.&lt;/strong&gt; The anchor's &lt;code&gt;href&lt;/code&gt; is already &lt;code&gt;/owner/repo&lt;/code&gt; — which is exactly what &lt;code&gt;https://api.github.com/repos{PL}&lt;/code&gt; needs. The join key comes from the page itself, so it can't drift out of sync.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;length_limit&lt;/code&gt; + &lt;code&gt;host_request_limiter&lt;/code&gt; keep you polite.&lt;/strong&gt; Top 5 repos, max 2 concurrent API calls. Unauthenticated GitHub API allows 60 requests/hour — a config that respects that is a config you can run on a schedule.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the general pattern for the modern web: the interesting &lt;em&gt;ranking&lt;/em&gt; lives in some HTML page, the &lt;em&gt;facts&lt;/em&gt; live in an API, and the join between them is exactly one &lt;code&gt;{PL}&lt;/code&gt; away.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the join key is a field, not the whole value
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;{PL}&lt;/code&gt; injects the &lt;em&gt;entire&lt;/em&gt; current value — perfect when your array items are scalars (story IDs, repo slugs). But often the items are &lt;strong&gt;objects&lt;/strong&gt; and the join key lives inside them. That's what expression placeholders are for. Book search → author enrichment on OpenLibrary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://openlibrary.org/search.json?q={{{FromInput=.}}}&amp;amp;limit=4&amp;amp;fields=title,author_key,first_publish_year"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"server_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"array_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"root_path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"item_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"int"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"first_publish_year"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"generated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://openlibrary.org/authors/{{{FromExp=fromJSON(fRes).author_key[0]}}}.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"server_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"null_on_error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"object_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"born"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"birth_date"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"died"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"death_date"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"limits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"host_request_limiter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"openlibrary.org"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run with &lt;code&gt;input&lt;/code&gt; = &lt;code&gt;dune&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dune"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1965&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Frank Herbert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"born"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8 October 1920"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"died"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"11 February 1986"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dune Messiah"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1969&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Frank Herbert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"born"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8 October 1920"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"died"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"11 February 1986"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Children of Dune"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1976&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Frank Herbert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"born"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8 October 1920"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"died"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"11 February 1986"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key line is the nested URL: &lt;code&gt;{{{FromExp=fromJSON(fRes).author_key[0]}}}&lt;/code&gt; is an &lt;a href="https://expr-lang.org/" rel="noopener noreferrer"&gt;expr-lang&lt;/a&gt; expression evaluated against the current item (&lt;code&gt;fRes&lt;/code&gt;) — parse it, take the first author key, splice it into the URL. Anything expr-lang can compute can become part of a request: pick a field, concatenate, add an offset, branch on a condition. And notice the output shape: each book keeps its own scalar fields while the enrichment lands as a nested &lt;code&gt;author&lt;/code&gt; object — the config's structure &lt;em&gt;is&lt;/em&gt; the response's structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't just return data — write the report
&lt;/h2&gt;

&lt;p&gt;Sometimes the deliverable isn't JSON in a chat window, it's &lt;em&gt;a file on disk&lt;/em&gt;. The &lt;code&gt;file_storage&lt;/code&gt; generated field turns any field into a write: the top-5 crypto coins, straight into a CSV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&amp;amp;order=market_cap_desc&amp;amp;per_page=5&amp;amp;page=1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"server_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"array_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"root_path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@this"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"item_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"generated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"file_storage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{HUMAN_INDEX},{{{name}}},{{{current_price}}},{{{price_change_percentage_24h}}}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"file_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"coins.csv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/tmp/fitter-report"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"append"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool call returns the written paths, and on disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; /tmp/fitter-report/coins.csv
1,Bitcoin,64778,-2.3
2,Ethereum,1881.01,-3.4
3,Tether,0.999265,0
4,BNB,566.81,-1.6
5,USDC,0.999672,0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going on in that &lt;code&gt;content&lt;/code&gt; template:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bare &lt;code&gt;{{{json.path}}}&lt;/code&gt; placeholders&lt;/strong&gt; pull fields straight out of the current item — &lt;code&gt;{{{name}}}&lt;/code&gt;, &lt;code&gt;{{{current_price}}}&lt;/code&gt; — no expressions needed for simple lookups. (Type the field as &lt;code&gt;object&lt;/code&gt; so the template sees the item's raw JSON.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;{HUMAN_INDEX}&lt;/code&gt; stamps the item's position&lt;/strong&gt; (1-based; &lt;code&gt;{INDEX}&lt;/code&gt; is the 0-based sibling). Fitter processes array items concurrently, so appends land in completion order — the rank column is what makes &lt;code&gt;sort -n&lt;/code&gt; restore truth. A nice reminder that this thing is genuinely parallel.&lt;/li&gt;
&lt;li&gt;There's a sibling &lt;code&gt;file&lt;/code&gt; field type that &lt;em&gt;downloads&lt;/em&gt; — point it at an image/PDF URL and the field's value becomes the local file path. Scrape a gallery, keep the pictures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combined with schedule-based service mode, this is a tiny ETL pipeline: fetch → shape → append to a growing CSV, every hour, defined entirely in one JSON document.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the site has no API
&lt;/h2&gt;

&lt;p&gt;The examples above hit JSON APIs, but the &lt;code&gt;response_type&lt;/code&gt; can just as well be &lt;code&gt;HTML&lt;/code&gt; (CSS selectors), &lt;code&gt;xpath&lt;/code&gt;, or &lt;code&gt;XML&lt;/code&gt; — and the connector can be a real browser when the page needs JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"connector_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTML"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/spa-page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"browser_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"playwright"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"browser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Chromium"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"install"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"stealth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chromium, Playwright (with stealth), and dockerized browsers are all built in — one static binary, no npm install.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why local-first matters
&lt;/h2&gt;

&lt;p&gt;The hosted scraping APIs are good products, but for agent workflows the local model has real advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auditable&lt;/strong&gt; — you can read exactly what the agent fetched and how. A config diff is reviewable; generated code in a sandbox somewhere is not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No keys, no metering&lt;/strong&gt; — your machine makes the requests. Nothing to sign up for, no per-page billing, no data passing through a third party.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusable by construction&lt;/strong&gt; — the same config runs via MCP, CLI (&lt;code&gt;fitter_cli --path config.json&lt;/code&gt;), a Go library call, or fitter's service mode with schedulers and notifiers (Telegram, webhook, Redis, file). Authored once by the model, promoted to a cron job when it proves useful.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hosting it for your team
&lt;/h2&gt;

&lt;p&gt;New in the latest release: the MCP server also speaks streamable HTTP, so you can run one fitter for the whole team. A minimal &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;fitter-mcp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/pxyup/fitter-mcp:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;FITTER_MCP_HTTP_ADDR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:8080"&lt;/span&gt;
      &lt;span class="na"&gt;FITTER_MCP_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${FITTER_MCP_AUTH_TOKEN:?set&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;token}"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# optional: mount reusable configs for fitter_run_file&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./configs:/configs:ro&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FITTER_MCP_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 16&lt;span class="si"&gt;)&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
curl http://localhost:8080/healthz   &lt;span class="c"&gt;# -&amp;gt; ok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every &lt;code&gt;/mcp&lt;/code&gt; request must then carry the bearer token, and the image's built-in healthcheck keeps your orchestrator honest. Register the endpoint in Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http fitter http://your-host:8080/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$FITTER_MCP_AUTH_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image is slim by design (binary + CA certs, &lt;code&gt;linux/amd64&lt;/code&gt; + &lt;code&gt;arm64&lt;/code&gt;): API/HTML scraping works out of the box, while browser-rendered pages need a release binary on a host with Chromium or Playwright.&lt;/p&gt;

&lt;p&gt;Client-side cancellation propagates all the way down to in-flight HTTP requests and browser sessions, so an abandoned agent run doesn't keep scraping in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/PxyUp/fitter" rel="noopener noreferrer"&gt;github.com/PxyUp/fitter&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;li&gt;MCP registry: &lt;code&gt;io.github.PxyUp/fitter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ready-made configs: &lt;a href="https://github.com/PxyUp/fitter/tree/master/examples" rel="noopener noreferrer"&gt;examples/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open Claude Code, add the server, and ask for some data you actually want every morning. The config it writes is yours to keep — that's the point.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Questions and config contributions welcome — the &lt;a href="https://github.com/PxyUp/fitter/tree/master/examples" rel="noopener noreferrer"&gt;examples folder&lt;/a&gt; takes PRs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>webscraping</category>
      <category>go</category>
    </item>
    <item>
      <title>Fitter - Open Source no-code tool for map-reduce data from different source and even more!</title>
      <dc:creator>Iurii Panarin</dc:creator>
      <pubDate>Wed, 30 Oct 2024 18:46:10 +0000</pubDate>
      <link>https://dev.to/pxyup/fitter-open-source-no-code-tool-for-map-reduce-data-from-different-source-and-even-more-10hd</link>
      <guid>https://dev.to/pxyup/fitter-open-source-no-code-tool-for-map-reduce-data-from-different-source-and-even-more-10hd</guid>
      <description>&lt;h2&gt;
  
  
  Hello everyone!
&lt;/h2&gt;

&lt;p&gt;I am &lt;a href="https://github.com/PxyUp" rel="noopener noreferrer"&gt;Pxyup&lt;/a&gt; and today i want represent for you by open source project Fitter.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/PxyUp" rel="noopener noreferrer"&gt;
        PxyUp
      &lt;/a&gt; / &lt;a href="https://github.com/PxyUp/fitter" rel="noopener noreferrer"&gt;
        fitter
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      New way for collect information from the API's/Websites
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;a href="https://github.com/PxyUp/fitter" rel="noopener noreferrer"&gt;Fitter + Fitter CLI&lt;/a&gt;&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Fitter - new way for collect information from the API's/Websites&lt;/p&gt;
&lt;p&gt;Fitter CLI - small cli command which provide result from Fitter for test/debug/home usage&lt;/p&gt;
&lt;p&gt;Fitter Lib - library which provide functional of fitter CLI as a library&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/PxyUp/fitter/blob/master/demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FPxyUp%2Ffitter%2Fraw%2Fmaster%2Fdemo.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Way to collect information&lt;/h1&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Server&lt;/strong&gt; - parsing response from some API's or http request(usage of http.Client)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser&lt;/strong&gt; - emulate real browser using chromium + docker + playwright/cypress and get DOM information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static&lt;/strong&gt; - parsing static string as data&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Format which can be parsed&lt;/h1&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt; - parsing JSON to get specific information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XML&lt;/strong&gt; - parsing xml tree to get specific information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML&lt;/strong&gt; - parsing dom tree to get specific information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XPath&lt;/strong&gt; - parsing dom tree to get specific information but by xpath&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Use like a library&lt;/h1&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;go get github.com/PxyUp/fitter&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-go notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;package&lt;/span&gt; main
&lt;span class="pl-k"&gt;import&lt;/span&gt; (
    &lt;span class="pl-s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="pl-s"&gt;"github.com/PxyUp/fitter/lib"&lt;/span&gt;
    &lt;span class="pl-s"&gt;"github.com/PxyUp/fitter/pkg/config"&lt;/span&gt;
    &lt;span class="pl-s"&gt;"log"&lt;/span&gt;
    &lt;span class="pl-s"&gt;"net/http"&lt;/span&gt;
)

&lt;span class="pl-k"&gt;func&lt;/span&gt; &lt;span class="pl-en"&gt;main&lt;/span&gt;() {
    &lt;span class="pl-s1"&gt;res&lt;/span&gt;, &lt;span class="pl-s1"&gt;err&lt;/span&gt; &lt;span class="pl-c1"&gt;:=&lt;/span&gt; &lt;span class="pl-s1"&gt;lib&lt;/span&gt;.&lt;span class="pl-en"&gt;Parse&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/PxyUp/fitter" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  How it was created
&lt;/h3&gt;

&lt;p&gt;In 2023, I worked on an idea called Trip Searcher:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.  You enter a budget.
2.  You specify a starting city or country.
3.  You set the trip duration and a range of possible start and end dates.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The Trip Searcher would monitor flights and return potential routes from the starting city, including total prices to various destinations, and send notifications to Telegram with:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.  Flight costs (parsed from Google or Kiwi).
2.  Hotel prices (from Airbnb or Booking).
3.  Food costs (retrieved from Numbeo).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;For this setup, I needed a list of countries, cities, and airport codes to plug into the sites mentioned. During development, I started thinking about how convenient it would be if all this information could be easily combined and parsed to streamline requests, which led to the idea for a project I call Fitter.&lt;/p&gt;

&lt;p&gt;P.S.: This project was for personal use.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fitter CLI
&lt;/h2&gt;

&lt;p&gt;A no-code map-reducer that returns data in user-friendly (JSON) or custom formats, suitable for storage in a database or transmission via HTTP.&lt;/p&gt;

&lt;p&gt;Features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Supports parsing through HTML (query), JSON (gjson), XML, and xpath parsers.&lt;/li&gt;
&lt;li&gt; Retrieves data as a browser would, using Docker, Playwright(+ stealth mode), HTTP Client, Cache, File, or propagated fields, with support for custom plugins.&lt;/li&gt;
&lt;li&gt; Provides proxy support for Playwright and HTTP clients.&lt;/li&gt;
&lt;li&gt; Can send or store information to a file, webhook, console, and more via plugins.&lt;/li&gt;
&lt;li&gt; Handles all data types: int, float, bool, array, object, null, and string.&lt;/li&gt;
&lt;li&gt; Combines (map-reduce) and transforms fields.&lt;/li&gt;
&lt;li&gt; Utilizes the powerful &lt;a href="https://github.com/expr-lang/expr" rel="noopener noreferrer"&gt;expr library&lt;/a&gt; for template syntax, which is available across the application.&lt;/li&gt;
&lt;li&gt; Offered as a standalone binary and Docker version.&lt;/li&gt;
&lt;li&gt; Allows limits on request counts or instances for browser/Docker usage.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://raw.githubusercontent.com/PxyUp/fitter/refs/heads/master/examples/cli/config_static_connector.json" rel="noopener noreferrer"&gt;Static generation&lt;/a&gt;:
&lt;/h4&gt;

&lt;p&gt;Here we will just generate static array from hardcoded&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./fitter_cli_v1.0.18-darwin-amd64 &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://raw.githubusercontent.com/PxyUp/fitter/refs/heads/master/examples/cli/config_static_connector.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"PAGE: 1 INDEX: 0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"PAGE: 2 INDEX: 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"PAGE: 3 INDEX: 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"PAGE: 4 INDEX: 3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"PAGE: 5 INDEX: 4"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://raw.githubusercontent.com/PxyUp/fitter/refs/heads/master/examples/cli/config_current_time.json" rel="noopener noreferrer"&gt;Get current time&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Get information from the website and return to user.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./fitter_cli_v1.0.18-darwin-amd64 &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://raw.githubusercontent.com/PxyUp/fitter/refs/heads/master/examples/cli/config_current_time.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Current time is: 19:18:51"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Get current Steam Sales
&lt;/h4&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;That will create &lt;em&gt;sales.md&lt;/em&gt; wile in provided directory&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  &lt;a href="https://raw.githubusercontent.com/PxyUp/fitter/refs/heads/master/examples/cli/config_cli.json" rel="noopener noreferrer"&gt;Get best news from HackerNews + Comment list for each&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;In this config we using template syntax for propagate result from the first request to next one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./fitter_cli_v1.0.18-darwin-amd64 &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://raw.githubusercontent.com/PxyUp/fitter/refs/heads/master/examples/cli/config_cli.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"internal_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://news.ycombinator.com/item?id=41975047"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"kids"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"response_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9db6ec73-3e35-4d06-b5eb-dbaa05a3a31d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"internal_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://news.ycombinator.com/item?id=41975981"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;amp;gt; We describe Flock as &amp;amp;amp;quot;Flutter+&amp;amp;amp;quot;. In other words, we do not want, or intend, to fork the Flutter community. Flock will remain constantly up to date with Flutter.&amp;amp;lt;p&amp;amp;gt;That was the first fear when I saw the title - splitting community and having two incompatible versions. Good to see it addressed in the post.&amp;amp;lt;p&amp;amp;gt;The second was just a fear of how it would complicate the development process, but it seems to be a drop-in replacement (just configuring FVM - Flutter Version Manager):&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;amp;lt;code&amp;amp;gt;   Configure .fvmrc to use Flock:   {     &amp;amp;amp;quot;flutter&amp;amp;amp;quot;: &amp;amp;amp;quot;master&amp;amp;amp;quot;,     &amp;amp;amp;quot;flutterUrl&amp;amp;amp;quot;: &amp;amp;amp;quot;https:&amp;amp;amp;#x2F;&amp;amp;amp;#x2F;github.com&amp;amp;amp;#x2F;Flutter-Foundation&amp;amp;amp;#x2F;flutter.git&amp;amp;amp;quot;   }&amp;amp;lt;/code&amp;amp;gt;&amp;amp;lt;/pre&amp;amp;gt;Flutter is the best thing that happened to UI development since Qt. Most people don&amp;amp;amp;#x27;t realize how many apps written in Flutter they use daily, simply because it&amp;amp;amp;#x27;s impossible to tell. And the frustration described in the post is felt by many CTOs and developers. Especially those who use Flutter for desktop and web. Flutter provides an amazing experience for desktop apps, and precisely because of that, it feels so frustrating when you stumble upon some stupid bug that has been open for a year or two and never gets prioritized. Usually, it&amp;amp;amp;#x27;s nothing critical, but still requires workarounds and wasting time.&amp;amp;lt;p&amp;amp;gt;I don&amp;amp;amp;#x27;t know, the idea of Flock sounds good, the main question is engaging the community. Hopefully, the author (who seem to be an ex-Flutter team member himself) have a good grasp on the state of the community.&amp;amp;lt;p&amp;amp;gt;Wishing luck to the project and going to keep an eye on the progress."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"comment"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41975981&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Back when I worked on GWT, we had trouble accepting outside contributions because the team had a mandate to support Googlers. That is, much like other libraries and tools at Google, changes could not break google3. This means &amp;amp;lt;i&amp;amp;gt;testing&amp;amp;lt;/i&amp;amp;gt; patches against google3 and either changing the patch, or fixing whatever code used it, and these are tasks that no outsider can do.&amp;amp;lt;p&amp;amp;gt;Shepherding these patches is no fun when you have your own changes to work on that are more important to the team.&amp;amp;lt;p&amp;amp;gt;We did something similar, by creating an external fork where changes could be tried out by the community, without necessarily being accepted into the internal version.&amp;amp;lt;p&amp;amp;gt;I think a fork &amp;amp;lt;i&amp;amp;gt;could&amp;amp;lt;/i&amp;amp;gt; work if there was enough external momentum, but even 20 people working full time would actually be pretty good for an open source project. How many developers will this fork attract? The fork would need to attract other businesses who can put people on it.&amp;amp;lt;p&amp;amp;gt;One downside is that the code isn&amp;amp;amp;#x27;t tested against google3. Sometimes you find actual bugs that way.&amp;amp;lt;p&amp;amp;gt;Edit: reading more closely, the complaint doesn&amp;amp;amp;#x27;t seem to be that patches weren&amp;amp;amp;#x27;t reviewed, but rather that bug reports weren&amp;amp;amp;#x27;t investigated. That&amp;amp;amp;#x27;s definitely something outside developers could do more of, and seems a lot easier than forking?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"comment"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"response_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"af15ca55-c45c-48a8-a18d-2fcbd7dd8f3b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41975765&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"internal_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://news.ycombinator.com/item?id=41975765"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://raw.githubusercontent.com/PxyUp/fitter/refs/heads/master/examples/cli/config_image_multiple.json" rel="noopener noreferrer"&gt;Scrape all images from website and store them locally&lt;/a&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./fitter_cli_v1.0.18-darwin-amd64 &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://raw.githubusercontent.com/PxyUp/fitter/refs/heads/master/examples/cli/config_image_multiple.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"/Users/pxyup/fitter/bin/1/basic-image.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"/Users/pxyup/fitter/bin/2/alt-text.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"/Users/pxyup/fitter/bin/3/no-size.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"/Users/pxyup/fitter/bin/4/size.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"/Users/pxyup/fitter/bin/5/image-with-title.png"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Fitter
&lt;/h2&gt;

&lt;p&gt;Fitter it is extended version of the Fitter CLI which have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Http server for trigger&lt;/li&gt;
&lt;li&gt;Return response as telegram message/webhook&lt;/li&gt;
&lt;li&gt;And that currently did not have documentation :)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;This tools can be used in different purpose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Web scrapper&lt;/li&gt;
&lt;li&gt;Data scrapper with plugins&lt;/li&gt;
&lt;li&gt;Produce specific load testing&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/PxyUp/it_life_berlin_fitter" rel="noopener noreferrer"&gt;Build chat bots&lt;/a&gt; - i use it for automate my telegram channel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example this job every day send best Dev.to aritcles:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h2&gt;
  
  
  Plans
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add more browser tools. Like click/scroll(currently can be done only by JS injection)&lt;/li&gt;
&lt;li&gt;Improve template syntax&lt;/li&gt;
&lt;li&gt;Add custom template editor + config editor&lt;/li&gt;
&lt;li&gt;May be will think about SASS for fitter CLI for run custom workflow for customers and return result to APP/Watch/etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Really wait for your feedback! Ask any question i will ask&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>go</category>
    </item>
    <item>
      <title>Fitter - open-source instrument for amazing scraping.</title>
      <dc:creator>Iurii Panarin</dc:creator>
      <pubDate>Tue, 30 Jan 2024 22:46:18 +0000</pubDate>
      <link>https://dev.to/pxyup/fitter-open-source-instrument-for-amazing-scraping-4aap</link>
      <guid>https://dev.to/pxyup/fitter-open-source-instrument-for-amazing-scraping-4aap</guid>
      <description>&lt;h3&gt;
  
  
  Hello everyone!
&lt;/h3&gt;

&lt;p&gt;I want to introduce &lt;a href="https://github.com/PxyUp/fitter"&gt;Fitter&lt;/a&gt; for you.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/PxyUp"&gt;
        PxyUp
      &lt;/a&gt; / &lt;a href="https://github.com/PxyUp/fitter"&gt;
        fitter
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      New way for collect information from the API's/Websites
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;h1&gt;
&lt;a href="https://github.com/PxyUp/fitter"&gt;Fitter + Fitter CLI&lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;Fitter - new way for collect information from the API's/Websites&lt;/p&gt;
&lt;p&gt;Fitter CLI - small cli command which provide result from Fitter for test/debug/home usage&lt;/p&gt;
&lt;p&gt;Fitter Lib - library which provide functional of fitter CLI as a library&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/PxyUp/fitter/blob/master/demo.gif"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LFp4tBWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://github.com/PxyUp/fitter/raw/master/demo.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
Way to collect information&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Server&lt;/strong&gt; - parsing response from some API's or http request(usage of http.Client)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser&lt;/strong&gt; - emulate real browser using chromium + docker + playwright/cypress and get DOM information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static&lt;/strong&gt; - parsing static string as data&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
Format which can be parsed&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt; - parsing JSON to get specific information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XML&lt;/strong&gt; - parsing xml tree to get specific information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML&lt;/strong&gt; - parsing dom tree to get specific information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XPath&lt;/strong&gt; - parsing dom tree to get specific information but by xpath&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
Use like a library&lt;/h1&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;go get github.com/PxyUp/fitter&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-go notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;package&lt;/span&gt; main
&lt;span class="pl-k"&gt;import&lt;/span&gt; (
    &lt;span class="pl-s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="pl-s"&gt;"github.com/PxyUp/fitter/lib"&lt;/span&gt;
    &lt;span class="pl-s"&gt;"github.com/PxyUp/fitter/pkg/config"&lt;/span&gt;
    &lt;span class="pl-s"&gt;"log"&lt;/span&gt;
    &lt;span class="pl-s"&gt;"net/http"&lt;/span&gt;
)

&lt;span class="pl-k"&gt;func&lt;/span&gt; &lt;span class="pl-en"&gt;main&lt;/span&gt;() {
    &lt;span class="pl-s1"&gt;res&lt;/span&gt;, &lt;span class="pl-s1"&gt;err&lt;/span&gt; &lt;span class="pl-c1"&gt;:=&lt;/span&gt; &lt;span class="pl-s1"&gt;lib&lt;/span&gt;.&lt;span class="pl-en"&gt;Parse&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/PxyUp/fitter"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This tool can do a lot of stuff:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read content by XML/XPath/Json/HTML selectors&lt;/li&gt;
&lt;li&gt;Emulate browser with docker/playwright/chromium&lt;/li&gt;
&lt;li&gt;Support proxy&lt;/li&gt;
&lt;li&gt;Global references&lt;/li&gt;
&lt;li&gt;Fallback on no empty fields&lt;/li&gt;
&lt;li&gt;Notification Telegram/Http/Redis/Console&lt;/li&gt;
&lt;li&gt;File downloading&lt;/li&gt;
&lt;li&gt;Full &lt;a href="https://github.com/PxyUp/fitter/blob/master/README.md"&gt;README.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Can work as golang library&lt;/li&gt;
&lt;li&gt;Support runtime golang plugins&lt;/li&gt;
&lt;li&gt;Work as CLI&lt;/li&gt;
&lt;li&gt;Works on Linux/Mac/Windows.&lt;/li&gt;
&lt;li&gt;Support different type of fields&lt;/li&gt;
&lt;li&gt;Support &lt;a href="https://expr-lang.org/"&gt;expression language&lt;/a&gt; for field and notification settings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;......&lt;/p&gt;

&lt;p&gt;N+1. &lt;strong&gt;Best and most important it is gluing of request&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Repository have a multiple examples for CLI/Fitter&lt;/p&gt;

&lt;h3&gt;
  
  
  Real world example of the problem
&lt;/h3&gt;

&lt;p&gt;Last week my friend need to monitor pool on some crypto stock. So here his problem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First of all you need get all user positions &lt;a href="https://docs.saucerswap.finance/v/developer/saucerswap-v2/liquidity-operations/get-user-positions"&gt;https://docs.saucerswap.finance/v/developer/saucerswap-v2/liquidity-operations/get-user-positions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;After that all stock pool &lt;a href="https://docs.saucerswap.finance/v/developer/saucerswap-v2/liquidity-operations/fetch-all-pools"&gt;https://docs.saucerswap.finance/v/developer/saucerswap-v2/liquidity-operations/fetch-all-pools&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;After that you should check if pool has user positions you should send notification.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's see how Fitter can solve this problem:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let me explain what is here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;environment variables:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;TELEGRAM_TOKEN&lt;/strong&gt; - line 95&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;USER_ID&lt;/strong&gt; - line 37&lt;/p&gt;

&lt;p&gt;So my friend need just run Fitter and add UserIds for Telegram notification(line 95):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxx &lt;span class="nv"&gt;USER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxx ./fitter &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;What happens in config:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;2.1 Creating Reference(line 3) on all pools and caching on 60 seconds(line 4). We take the response and create an array of the objects with two fields tokenA and tokenB.&lt;/p&gt;

&lt;p&gt;2.2 Creating Reference(line 33) on AccountId will be just string from ENV.&lt;/p&gt;

&lt;p&gt;2.3 We create items for monitoring every 10 seconds(line 88) which take values from the server via injecting AccountIdRef(line 52). Response it is array of objects with two field: first it is (line 66) - template string with injecting token name; second is boolean field which show if pair in pool(line 71)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next we will inform if some of the values in array is true(line 93).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will receive notification in Telegram:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tokenA=USDC tokenB=USDC[hts]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tokenA=USDC tokenB=USDT"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>go</category>
    </item>
    <item>
      <title>SafeStorageBot - keep’s your secrets in Telegram</title>
      <dc:creator>Iurii Panarin</dc:creator>
      <pubDate>Fri, 20 May 2022 15:42:09 +0000</pubDate>
      <link>https://dev.to/pxyup/safestoragebot-keeps-your-secrets-in-telegram-1i5l</link>
      <guid>https://dev.to/pxyup/safestoragebot-keeps-your-secrets-in-telegram-1i5l</guid>
      <description>&lt;p&gt;The Telegram team announced the Saved Messages tab quite a while ago. Over time, my friends and I noticed that some of our passwords from services began to appear there as well, and “Saved Messages” is already being used as a password repository.&lt;/p&gt;

&lt;p&gt;It’s quite convenient, but there are some disadvantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Passwords are not encrypted.&lt;/li&gt;
&lt;li&gt;It is hard to search without tags, because there is other information&lt;/li&gt;
&lt;li&gt;It’s inconvenient to associate the service with the password&lt;/li&gt;
&lt;li&gt;You have to select when copying (which is not always convenient when there are special characters)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Solve this problem securely for passwords with a bot, before the release of Telegram WebApp was impossible with one bot(you can encrypt separately and send the result):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No client side(code that can be verified)&lt;/li&gt;
&lt;li&gt;Send unencrypted passwords to server is unsafe&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the advantage of WebApp this can be done (the main thing is to think up and remember the master-password):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Encrypt the password with a master password using Javascript (crypto API/crypto-JS) on the client side&lt;/li&gt;
&lt;li&gt;Send the encrypted password to the server (there we encrypt the password a couple more times to secure the database)&lt;/li&gt;
&lt;li&gt;When we need a password, we request it and decrypt it using the master password on the client side&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s how this bot came about.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://t.me/SafeStorageBot"&gt;BOT LINK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below I will show a short video of the bot:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/VEZt9bAXH74"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You add a password with the title&lt;/li&gt;
&lt;li&gt;You enter the master password for encryption&lt;/li&gt;
&lt;li&gt;Send title + encrypted password to the server (master-password is never sent)&lt;/li&gt;
&lt;li&gt;On the server, encrypt the password and userId a second time with the server master-password&lt;/li&gt;
&lt;li&gt;The entry is saved in the database
……&lt;/li&gt;
&lt;li&gt;You request the password&lt;/li&gt;
&lt;li&gt;The entry is retrieved from the database and decrypted with the server master-password&lt;/li&gt;
&lt;li&gt;Sent to the client side&lt;/li&gt;
&lt;li&gt;You enter your master password and decrypt on the client side using javascript&lt;/li&gt;
&lt;li&gt;You see the decrypted password and can copy it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The client part of the application is posted in the repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SafeStorageBot"&gt;
        SafeStorageBot
      &lt;/a&gt; / &lt;a href="https://github.com/SafeStorageBot/frontend_bot"&gt;
        frontend_bot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Frontend for bot
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;h1&gt;
TelegramPasswords&lt;/h1&gt;
&lt;p&gt;This project was generated with &lt;a href="https://github.com/angular/angular-cli"&gt;Angular CLI&lt;/a&gt; version 13.3.5.&lt;/p&gt;
&lt;h2&gt;
Development server&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;ng serve&lt;/code&gt; for a dev server. Navigate to &lt;code&gt;http://localhost:4200/&lt;/code&gt;. The application will automatically reload if you change any of the source files.&lt;/p&gt;
&lt;h2&gt;
Code scaffolding&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;ng generate component component-name&lt;/code&gt; to generate a new component. You can also use &lt;code&gt;ng generate directive|pipe|service|class|guard|interface|enum|module&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
Build&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;ng build&lt;/code&gt; to build the project. The build artifacts will be stored in the &lt;code&gt;dist/&lt;/code&gt; directory.&lt;/p&gt;
&lt;h2&gt;
Running unit tests&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;ng test&lt;/code&gt; to execute the unit tests via &lt;a href="https://karma-runner.github.io" rel="nofollow"&gt;Karma&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
Running end-to-end tests&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;ng e2e&lt;/code&gt; to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.&lt;/p&gt;
&lt;h2&gt;
Further help&lt;/h2&gt;
&lt;p&gt;To get more help on the Angular CLI use &lt;code&gt;ng help&lt;/code&gt; or go check out the &lt;a href="https://angular.io/cli" rel="nofollow"&gt;Angular CLI Overview and Command Reference&lt;/a&gt; page.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/SafeStorageBot/frontend_bot"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;With the command &lt;strong&gt;/version&lt;/strong&gt; you can always see the commit number of the client part of the application and see the code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SafeStorageBot/frontend_bot/blob/master/src/app/utils/crypto.ts"&gt;Frontend encryption module&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have long thought about monetisation and after consulting with friends I settled on the option 3 passwords can always be stored, and for a donation of 3 euros a month you can store any number&lt;/p&gt;

&lt;p&gt;Thank you for your attention!&lt;/p&gt;

&lt;p&gt;PS: Let me take advantage of the opportunity to be promoted again:&lt;br&gt;
&lt;a href="https://t.me/SafeStorageBot"&gt;BOT LINK&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bot</category>
      <category>telegram</category>
      <category>opensource</category>
      <category>angular</category>
    </item>
    <item>
      <title>How I built a super fast JS/TS framework</title>
      <dc:creator>Iurii Panarin</dc:creator>
      <pubDate>Fri, 26 Apr 2019 14:52:46 +0000</pubDate>
      <link>https://dev.to/pxyup/how-i-built-a-super-fast-js-framework-4agb</link>
      <guid>https://dev.to/pxyup/how-i-built-a-super-fast-js-framework-4agb</guid>
      <description>&lt;h1&gt;
  
  
  How do other frameworks operate?
&lt;/h1&gt;

&lt;p&gt;What if we didn't use Virtual DOM at all, instead work with real DOM instead? To answer this, we first need to understand how most frameworks work, to better illustrate this I drew a small example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fg25b38qhbuf2se3ultxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fg25b38qhbuf2se3ultxp.png" alt="img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Violet are DOM/VDOM nodes, Blue = state, Red = diffing, Green = patching. I should explain what happens in this picture. So most of the frameworks that have state and DOM, act like this when something in the state is modified. In this example, state.bg has changed. So now we iterate through all of the nodes (those 5 steps) and renders them. If something is changed, then patching happens where rendered stuff goes to actual DOM (green action). Ok, that's cool, but why do we need to iterate every single node (note that here come those diffing algorithms that compete with each other and some does diff differently) when only state.bg changes?!..&lt;/p&gt;

&lt;p&gt;So back to my original question “Why do we need Virtual DOM ?”, the answer is to iterate through all of DOM more quickly. Ok, so what if we didn't iterate?&lt;/p&gt;

&lt;h1&gt;
  
  
  Utopia way of doing this
&lt;/h1&gt;

&lt;p&gt;But I want to show you the way that in my head it should work without diffing nor iterating, nor Vnodes for that matter as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fdqb4xxm4q2w1w4oemihe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fdqb4xxm4q2w1w4oemihe.png" alt="img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So in this utopia way we changed the same state.bg and there is no iteration (so no need for Virtual DOM), only one render (that single red dot), only one single parameter/attribute/node modifies which is affected by state.bg changes. Much less unnecessary iteration, unnecessary memory usage for virtual nodes, much less rendering = much faster.&lt;/p&gt;

&lt;h1&gt;
  
  
  Motivation
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;1. Small bundle size&lt;/em&gt;&lt;br&gt;
Many of the modern frameworks are very large. I honestly do not believe that the application “Hello World” should weigh more than 10kb. &lt;br&gt;
To solve this problem, I decided to use a declarative way to describe the components. This has a positive effect on the final size of the application and allows you to use the tree-shaking directly in the component template.&lt;br&gt;
&lt;a href="https://stackblitz.com/edit/typescript-cuat9d" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;2. Truly reactive&lt;/em&gt;&lt;br&gt;
I really wanted to implement reactivity as it was done in VueJS. If you change the entity of something, then the data on the page also changes, and if you change the data, the entity changes.&lt;br&gt;
&lt;a href="https://stackblitz.com/edit/typescript-ddsu5c" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;3. Pure reusable components&lt;/em&gt;&lt;br&gt;
Any framework should be able to create life-cycle-aware components. This removes duplication of code and allows the component to be reused in several places.&lt;br&gt;
&lt;a href="https://stackblitz.com/edit/typescript-cf54fk" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;4. Conditional render and list render directives&lt;/em&gt;&lt;br&gt;
I really like the ReactJS, very straight, the first acquaintance, it was just wonderful. However, if you need nested conditional rendering, you will have to either use component wrappers or make ternary expressions that are difficult to read.&lt;br&gt;
&lt;a href="https://stackblitz.com/edit/typescript-gssmle" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Benchmark application
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/edit/typescript-p35cgr" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Another frameworks
&lt;/h2&gt;

&lt;p&gt;React (Stack) — &lt;a href="https://claudiopro.github.io/react-fiber-vs-stack-demo/stack.html" rel="noopener noreferrer"&gt;https://claudiopro.github.io/react-fiber-vs-stack-demo/stack.html&lt;/a&gt;&lt;br&gt;
React (Fiber) — &lt;a href="https://radi.js.org/fiber/Fiber%20Example.htm" rel="noopener noreferrer"&gt;https://radi.js.org/fiber/Fiber%20Example.htm&lt;/a&gt;&lt;br&gt;
Stencil.js — &lt;a href="https://stencil-fiber-demo.firebaseapp.com/perf.html" rel="noopener noreferrer"&gt;https://stencil-fiber-demo.firebaseapp.com/perf.html&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Performance test
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://pxyup.github.io/Revact/" rel="noopener noreferrer"&gt;https://pxyup.github.io/Revact/&lt;/a&gt; - try with throttling x6 times.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html" rel="noopener noreferrer"&gt;https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html&lt;/a&gt; (old name faster-dom)&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Link
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/PxyUp/Revact" rel="noopener noreferrer"&gt;https://github.com/PxyUp/Revact&lt;/a&gt; - source&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pxyup.github.io/Revact/" rel="noopener noreferrer"&gt;https://pxyup.github.io/Revact/&lt;/a&gt; - DEMO&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/RyuuGan/html2FastDom" rel="noopener noreferrer"&gt;https://github.com/RyuuGan/html2FastDom&lt;/a&gt; - Html transpiller&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>react</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Lightweight replacement of React + MobX</title>
      <dc:creator>Iurii Panarin</dc:creator>
      <pubDate>Mon, 25 Mar 2019 18:47:23 +0000</pubDate>
      <link>https://dev.to/pxyup/lightweight-replacement-of-react--mobx-22gd</link>
      <guid>https://dev.to/pxyup/lightweight-replacement-of-react--mobx-22gd</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/PxyUp/FastDom"&gt;FastDom&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lightweight replacement of React + MobX (I hope in future Angular/Vue), which does not use the virtual DOM comparison, but the re-render of only the changed parts. Abandon the HTML template in favor of their interpretation in JS, give to us tree-shaking is components/templates and the speed of work increases since the time to parse the template is zero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://thepracticaldev.s3.amazonaws.com/i/kedjptyl326dy2xwqycj.png"&gt;DEMO LINK&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackblitz.com/edit/typescript-wgjbzf"&gt;DEMO at StackBlitz&lt;/a&gt;&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Size - &lt;strong&gt;4.1 kB&lt;/strong&gt; or &lt;strong&gt;1.38 kB&lt;/strong&gt; gzipped.&lt;/li&gt;
&lt;li&gt;The library rewrites only changes and only when it is necessary.&lt;/li&gt;
&lt;li&gt;Performance - &lt;strong&gt;guarantee 60 fps&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Names of imported functions and classes are not finally and &lt;em&gt;can be discussed&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;There is &lt;strong&gt;a tree-shaking for components and templates !!!&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Vue conditional render based on breakpoint</title>
      <dc:creator>Iurii Panarin</dc:creator>
      <pubDate>Tue, 23 Oct 2018 08:35:31 +0000</pubDate>
      <link>https://dev.to/pxyup/vue-conditional-render-based-on-breakpoint-3a73</link>
      <guid>https://dev.to/pxyup/vue-conditional-render-based-on-breakpoint-3a73</guid>
      <description>&lt;p&gt;Good day all! I was create directive for conditionals renders based on screen size, support resize event.&lt;br&gt;
&lt;a href="https://github.com/PxyUp/vue-not-visible"&gt;https://github.com/PxyUp/vue-not-visible&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/vue-not-visible"&gt;https://www.npmjs.com/package/vue-not-visible&lt;/a&gt;&lt;br&gt;
Demo: &lt;a href="https://pxyup.github.io/vue-not-visible/index.html"&gt;https://pxyup.github.io/vue-not-visible/index.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>npm</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Angular Virtual Table</title>
      <dc:creator>Iurii Panarin</dc:creator>
      <pubDate>Mon, 22 Oct 2018 23:54:22 +0000</pubDate>
      <link>https://dev.to/pxyup/angular-virtual-table-321o</link>
      <guid>https://dev.to/pxyup/angular-virtual-table-321o</guid>
      <description>&lt;p&gt;Good evening, I created virtual scroll table based on material virtual scroll. This table support filtering, sorting and you can easy customize that. Demo included&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/PxyUp/ng-virtual-table"&gt;https://github.com/PxyUp/ng-virtual-table&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://pxyup.github.io/ng-virtual-table"&gt;https://pxyup.github.io/ng-virtual-table&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In future planned so many options like drag and drop, more filter types and more like that. Thanks for any help :)&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>rxjs</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
