<?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: Priyesh Dabre</title>
    <description>The latest articles on DEV Community by Priyesh Dabre (@priyeshdabre).</description>
    <link>https://dev.to/priyeshdabre</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%2F4152667%2F493d0ef7-b629-46d5-b9ae-4de2b88956ab.jpg</url>
      <title>DEV Community: Priyesh Dabre</title>
      <link>https://dev.to/priyeshdabre</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/priyeshdabre"/>
    <language>en</language>
    <item>
      <title>🦥 Sloth Mode: A Local AI Assistant That Does the Boring Work for You</title>
      <dc:creator>Priyesh Dabre</dc:creator>
      <pubDate>Sun, 25 Oct 2026 14:39:13 +0000</pubDate>
      <link>https://dev.to/priyeshdabre/sloth-mode-a-local-ai-assistant-that-does-the-boring-work-for-you-1gp4</link>
      <guid>https://dev.to/priyeshdabre/sloth-mode-a-local-ai-assistant-that-does-the-boring-work-for-you-1gp4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvm2x76llq7a23i6evqxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvm2x76llq7a23i6evqxz.png" alt=" " width="800" height="475"&gt;&lt;/a&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;Sloth Mode&lt;/strong&gt; — a local-first AI document assistant designed for people who want to spend less time dealing with information and more time doing things they actually enjoy.&lt;/p&gt;

&lt;p&gt;We all have documents, meeting notes, and random text files that take time to read and organize. Sloth Mode helps reduce that effort by turning lengthy text documents into concise, useful summaries.&lt;/p&gt;

&lt;p&gt;With Sloth Mode, you can:&lt;/p&gt;

&lt;p&gt;📄 Select a text document from your local documents folder.&lt;br&gt;
🧠 Generate an AI-powered summary with important points, decisions, and action items.&lt;br&gt;
🖥️ Use a simple browser-based interface built with Streamlit.&lt;br&gt;
⬇️ Download the generated summary for later use.&lt;br&gt;
The goal is simple: let AI handle the repetitive reading so you don't have to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GitHub repository: [&lt;a href="https://github.com/priyeshdabre07/sloth-mode" rel="noopener noreferrer"&gt;https://github.com/priyeshdabre07/sloth-mode&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;The project is built with Python and is designed to be easy to run and modify.&lt;/p&gt;

&lt;p&gt;Repository contents:&lt;/p&gt;

&lt;p&gt;ui.py — Streamlit user interface.&lt;br&gt;
app.py — command-line document summarizer.&lt;br&gt;
documents/ — sample text documents for testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I Built It&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built Sloth Mode using a small, local AI stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python — application logic and document processing.&lt;/li&gt;
&lt;li&gt;Streamlit — browser-based user interface.&lt;/li&gt;
&lt;li&gt;Ollama — local model runtime and inference API.&lt;/li&gt;
&lt;li&gt;Qwen 2.5 3B — the open-weight language model that generates summaries.
The application reads text files from a local folder, sends their contents to the Ollama service running on my Mac, and displays the model's response in the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The workflow is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose a text document.&lt;/li&gt;
&lt;li&gt;Send its contents to the locally running model.&lt;/li&gt;
&lt;li&gt;Generate a concise summary with important points and action items.&lt;/li&gt;
&lt;li&gt;Display and download the result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why Does Open Innovation Matter?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For Sloth Mode, open-weight AI makes local, private-by-design document assistance possible without depending on a proprietary cloud AI API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy and control:&lt;/strong&gt; Documents can be processed on my own computer instead of being uploaded to an external AI provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offline potential:&lt;/strong&gt; Once the model and software dependencies are installed, the core inference workflow can run without an internet connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No per-request API fees:&lt;/strong&gt; Local inference avoids usage-based charges from a hosted model API, although it still uses electricity and computer resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Freedom to experiment:&lt;/strong&gt; I can change the model, modify prompts, adjust the summarization workflow, and extend the application without being locked into one proprietary AI endpoint.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>LocalAI Invoice Copilot: A Private Invoice Clerk for Freelancers</title>
      <dc:creator>Priyesh Dabre</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:49:14 +0000</pubDate>
      <link>https://dev.to/priyeshdabre/localai-invoice-copilot-a-private-invoice-clerk-for-freelancers-ep</link>
      <guid>https://dev.to/priyeshdabre/localai-invoice-copilot-a-private-invoice-clerk-for-freelancers-ep</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87t2j5ptx3zqfjaq54e5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87t2j5ptx3zqfjaq54e5.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;br&gt;
LocalAI Invoice Copilot turns text-based PDF invoices into structured records that freelancers and small businesses can review and export as CSV. It extracts details such as vendor, invoice number, date, tax, and total, then flags missing fields, possible duplicates, and totals that do not add up.&lt;/p&gt;

&lt;p&gt;The people most likely to pay for it are freelancers and small teams who are tired of manually copying invoice details into spreadsheets, but don’t want to send financial documents to a hosted AI service.&lt;/p&gt;

&lt;p&gt;It’s a prototype: records are kept in memory, and extracted values should be reviewed before use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo&lt;/strong&gt;&lt;br&gt;
There’s no hosted demo yet. The app runs locally, which is also how the invoice text stays on your machine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Ollama and download the model with ollama pull qwen2.5:3b.&lt;/li&gt;
&lt;li&gt;Install the Python dependencies with pip install -r requirements.txt.&lt;/li&gt;
&lt;li&gt;Start the app with python -m streamlit run app.py.&lt;/li&gt;
&lt;li&gt;Load the synthetic demo invoice or upload a text-based PDF, review the extracted fields, and download the CSV.&lt;/li&gt;
&lt;li&gt;Scanned PDFs are not supported in the app yet; they need OCR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
Source code: [&lt;a href="https://github.com/priyeshdabre07/localai-invoice-copilot" rel="noopener noreferrer"&gt;https://github.com/priyeshdabre07/localai-invoice-copilot&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;The app uses pypdf to read PDF text, asks the local model for structured JSON, and provides an editable review table with basic validation before CSV export.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I Built It&lt;/strong&gt;&lt;br&gt;
The app is built with Python and Streamlit. It sends invoice text to Qwen2.5 3B through Ollama’s local API, using a JSON schema and a prompt that tells the model to leave uncertain fields blank rather than invent values. pypdf extracts selectable text from PDFs, and pandas handles the review table and CSV export.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Does Open Innovation Matter?&lt;/strong&gt;&lt;br&gt;
Invoices contain financial and business information that freelancers may not want to send to a third-party AI service. With local inference, invoice text stays on the user’s machine instead of going to a hosted LLM API. After downloading the model, there’s no per-invoice API fee; the tradeoff is that inference uses the user’s own hardware.&lt;/p&gt;

&lt;p&gt;Using an open-weight model also makes the extraction prompt and expected fields easy to inspect and adapt to different workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prize Categories&lt;/strong&gt;&lt;br&gt;
Entering the overall Side Hustle challenge. No partner category.&lt;/p&gt;

&lt;p&gt;#devchallenge #hf26challenge&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Building a tiny choose-your-own-adventure with vanilla JavaScript</title>
      <dc:creator>Priyesh Dabre</dc:creator>
      <pubDate>Fri, 16 Oct 2026 06:44:55 +0000</pubDate>
      <link>https://dev.to/priyeshdabre/building-a-tiny-choose-your-own-adventure-with-vanilla-javascript-200o</link>
      <guid>https://dev.to/priyeshdabre/building-a-tiny-choose-your-own-adventure-with-vanilla-javascript-200o</guid>
      <description>&lt;p&gt;I wanted to build a small adventure game that felt like stepping into a story: a moonlit forest, a few meaningful choices, and more than one way for the journey to end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mosslight&lt;/strong&gt; is a browser game where you explore the woods, collect a few items, and search for the moon bell. &lt;a href="https://simpleadventuregame.vercel.app" rel="noopener noreferrer"&gt;Play it here&lt;/a&gt;. It’s built with plain HTML, CSS, and JavaScript—no framework, build step, or package dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Put the story in data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each scene is an object with its own text and choices. A choice can move the story forward, add an item, or change the ending:&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="err"&gt;title:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A river with no end"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;choices:&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="err"&gt;label:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Offer a moonleaf to the water"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;requires:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"moonleaf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;consume:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"moonleaf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;next:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tower"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;flag:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"river_blessing"&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="err"&gt;label:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cross on the slippery stones"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;next:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tower"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;health:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&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;Keeping the choices with the scene made the story easy to expand and helped keep the game logic out of the page markup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep state small&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The game tracks the current scene, warmth, pocket items, and a few story flags. When a player chooses something, the game updates that state and renders the next scene:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;choose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addUnique&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consume&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addUnique&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;health&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;health&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;health&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;health&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;health&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ending&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Story text is rendered as text rather than injected HTML. After a choice, focus moves to the new scene heading so keyboard players can follow the transition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make the atmosphere part of the interface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The forest illustration is made from CSS shapes and gradients, so the game needs no image assets. The layout adapts for smaller screens, and the firefly animation respects reduced-motion preferences.&lt;/p&gt;

&lt;p&gt;The result is a short game with different routes, item-dependent choices, and endings shaped by what you did along the way. I tested a complete route to the moon-bell ending, the out-of-warmth ending, and the restart flow in the browser.&lt;/p&gt;

&lt;p&gt;There’s room to grow the story, but keeping the scene data and game state simple made it possible to get a playable version running quickly. &lt;a href="https://simpleadventuregame.vercel.app" rel="noopener noreferrer"&gt;Try Mosslight&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>CrumbCraft AI: An Offline, Voice-First Agent for My Baker Friend Niki 🎂🤖</title>
      <dc:creator>Priyesh Dabre</dc:creator>
      <pubDate>Sun, 04 Oct 2026 14:47:40 +0000</pubDate>
      <link>https://dev.to/priyeshdabre/crumbcraft-ai-an-offline-voice-first-agent-for-my-baker-friend-niki-4gna</link>
      <guid>https://dev.to/priyeshdabre/crumbcraft-ai-an-offline-voice-first-agent-for-my-baker-friend-niki-4gna</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built CrumbCraft AI, a hands-free, voice-activated baking and cake decorating assistant designed specifically for my friend Niki.&lt;/p&gt;

&lt;p&gt;Niki runs a boutique home bakery specializing in custom, multi-tiered cakes. Her process is creative and precise, but working in her basement prep kitchen presents unique real-world challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Flour-Covered Hands: When she's piping Swiss Meringue buttercream or sculpting fondant, touching a tablet or phone to look up recipe scalings or substitution math washes 10+ minutes down the drain in hand-sanitizing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strict Allergen Safety: A math miscalculation when scaling a gluten-free or vegan recipe for a sensitive client can ruin an event—or pose real health risks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kitchen Dead Zones: Her basement prep kitchen has unreliable Wi-Fi. Cloud-only voice assistants fail right when she needs an immediate unit conversion mid-bake.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CrumbCraft AI solves this by running as a 100% offline, hands-free voice loop on her kitchen laptop. Niki simply speaks her question out loud, and CrumbCraft processes her speech, calculates exact recipe scalings, verifies allergen rules, and speaks the answer back—all with zero internet connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo&lt;/strong&gt;&lt;br&gt;
Here is a recording of CrumbCraft AI running locally with zero Wi-Fi connection, listening through the microphone and speaking answers back via native audio:&lt;br&gt;
{&lt;a href="https://drive.google.com/file/d/1QmiBeJ2JV8rOoBrSpMsIlhqiAUh3gDhj/view?usp=share_link" rel="noopener noreferrer"&gt;https://drive.google.com/file/d/1QmiBeJ2JV8rOoBrSpMsIlhqiAUh3gDhj/view?usp=share_link&lt;/a&gt;}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
You can check out the open-source repository and build setup below:&lt;br&gt;
{&lt;a href="https://github.com/priyeshdabre07/crumbcraft-ai" rel="noopener noreferrer"&gt;https://github.com/priyeshdabre07/crumbcraft-ai&lt;/a&gt;}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Tech Stack&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent Framework: Mastra (@mastra/core)&lt;/li&gt;
&lt;li&gt;Local LLM Engine: Ollama running Google's open-weight gemma4:e4b&lt;/li&gt;
&lt;li&gt;Local Speech Recognition (STT): OpenAI Whisper (small.en via whisper-node / whisper.cpp)&lt;/li&gt;
&lt;li&gt;Local Audio Recording &amp;amp; TTS: SoX (rec) &amp;amp; macOS Native Speech Engine (say)&lt;/li&gt;
&lt;li&gt;Local Memory Store: Embedded JSON Recipe Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How I Built It&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CrumbCraft AI is designed around a fully local, privacy-first pipeline where open-source components handle every step of the voice agent loop:&lt;br&gt;
 +-----------------------------------------------------------------------+&lt;br&gt;
 |                          KITCHEN WORKSPACE                            |&lt;br&gt;
 |                                                                       |&lt;br&gt;
 |   🎙️ Microphones Capture Speech   ---&amp;gt;   🔊 Speakers Output Audio     |&lt;br&gt;
 +----------------------------------+------------------------------------+&lt;br&gt;
                                    |&lt;br&gt;
                                    v&lt;br&gt;
 +-----------------------------------------------------------------------+&lt;br&gt;
 |                     CRUMBCRAFT LOCAL PIPELINE                         |&lt;br&gt;
 |                                                                       |&lt;br&gt;
 | 1. Speech-to-Text: OpenAI Whisper (small.en running locally)          |&lt;br&gt;
 |                                  │                                    |&lt;br&gt;
 |                                  v                                    |&lt;br&gt;
 | 2. Agent Orchestration: Mastra Framework                              |&lt;br&gt;
 |    ├── LLM Reasoning: Google Gemma 4 (gemma4:e4b via Ollama)          |&lt;br&gt;
 |    ├── Deterministic Tools: frostingScalerTool &amp;amp; allergenCheckerTool  |&lt;br&gt;
 |    └── Embedded Memory: local_recipes.json Database                   |&lt;br&gt;
 |                                  │                                    |&lt;br&gt;
 |                                  v                                    |&lt;br&gt;
 | 3. Text-to-Speech: Native macOS 'say' Engine / Local Audio Synthesis   |&lt;br&gt;
 +-----------------------------------------------------------------------+&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Deterministic Baking Tools with Mastra:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We defined specialized tools within Mastra so the agent doesn't hallucinate baking math:&lt;br&gt;
TypeScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createTool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mastra/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;searchLocalRecipes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../db/localDb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frostingScalerTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frosting-scaler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Calculates total frosting volume and key ingredient weights based on cake tier diameters.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tierSizesInInches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Array of tier diameters in inches, e.g. [6, 8, 10]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;frostingType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Type of frosting, e.g., Swiss Meringue Buttercream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;totalCupsNeeded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;butterGrams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;sugarGrams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tierSizesInInches&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalSurfaceArea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tierSizesInInches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalCupsNeeded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;totalSurfaceArea&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;totalCupsNeeded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;butterGrams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalCupsNeeded&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;115&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="na"&gt;sugarGrams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalCupsNeeded&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Local Open Weights with Gemma 4:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We targeted &lt;strong&gt;gemma4:e4b&lt;/strong&gt; running locally via Ollama. It strikes the perfect balance for Apple Silicon (M4 with 16GB Unified Memory): delivering native function-calling capabilities, zero network latency, and low memory usage (~6.6 GB RAM) so the machine stays cool and responsive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Local Voice Pipeline:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Input: Audio is captured directly from the microphone using sox and transcribed locally via Whisper (small.en).&lt;br&gt;
Output: Speech responses are generated instantly through macOS's native TTS engine (say), eliminating cloud per-character API fees.&lt;/p&gt;

&lt;p&gt;Why Does Open Innovation Matter?&lt;/p&gt;

&lt;p&gt;Open-source AI was not just a convenience for this project—it was an absolute requirement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kitchen Reliability (Zero Internet Dependency): Niki's basement prep room is an internet dead zone. Cloud AI models (like ChatGPT or proprietary voice APIs) freeze or fail completely when connection drops. Open-weight models like Gemma 4 run 100% locally on device, guaranteeing that her voice assistant works every single time.&lt;/li&gt;
&lt;li&gt;Data Privacy for Client Relationships: Niki stores client allergy histories, family dietary preferences, and proprietary recipe ratios. Keeping execution entirely local ensures zero client data or custom recipes are uploaded to external training servers.&lt;/li&gt;
&lt;li&gt;Zero Operating Cost: Running open-source models via Ollama and local speech engines means CrumbCraft AI costs $0.00/month to run. An artisan baker shouldn't have to worry about token billing while mixing batter.&lt;/li&gt;
&lt;li&gt;Custom Tooling Control: Proprietary black-box endpoints can hallucinate substitution advice. Open frameworks like Mastra allow us to inspect, trace, and strictly enforce deterministic rule checking for allergen safety.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Prize Categories&lt;/strong&gt;&lt;br&gt;
Best Use of Gemma: Used gemma4:e4b locally via Ollama as the core reasoning engine for unit conversions, allergen substitutions, and tool calls.&lt;br&gt;
Best Use of Mastra: Built the entire agent workflow, tool execution layer, and structured response pipeline using the Mastra TypeScript framework.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
