<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Blogs]]></title><description><![CDATA[Monologue ]]></description><link>https://blog.loarsaw.de</link><generator>RSS for Node</generator><lastBuildDate>Thu, 09 Apr 2026 19:01:40 GMT</lastBuildDate><atom:link href="https://blog.loarsaw.de/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Build Interactive Code Playgrounds with Sandpack (2026 Edition)]]></title><description><![CDATA[Recently it was announced that Sandpack will no longer be actively maintained. Not really great news to wake up to, but C'est la vie. I personally was introduced to Sandpack when going through the blo]]></description><link>https://blog.loarsaw.de/how-to-build-interactive-code-playgrounds-with-sandpack-2026-edition</link><guid isPermaLink="true">https://blog.loarsaw.de/how-to-build-interactive-code-playgrounds-with-sandpack-2026-edition</guid><category><![CDATA[CodeSandbox]]></category><category><![CDATA[code editor]]></category><category><![CDATA[playground]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Wed, 18 Mar 2026 07:25:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/68c8ed1569a5610bb011f6ce/cebe780a-6cfb-4a96-942d-4a2c360f1ef8.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently it was announced that Sandpack will no longer be actively maintained. Not really great news to wake up to, but C'est la vie. I personally was introduced to Sandpack when going through the blog of Josh W. Comeau (<a href="https://www.joshwcomeau.com/">https://www.joshwcomeau.com/</a>).</p>
<p>If you've ever used the React documentation or seen a blog post where you can edit code and see a live preview instantly, you've likely seen Sandpack in action.</p>
<p>Even though CodeSandbox has recently pivoted toward AI infrastructure, Sandpack remains one of the best ways to embed an interactive coding experience into your website. In this guide, we'll walk through how to set it up, what you need to know about its current status, and whether it's still the right choice for your project.</p>
<h2>What is Sandpack?</h2>
<p>Sandpack is an open-source component toolkit that brings the power of the CodeSandbox bundler directly to your React app. It allows you to:</p>
<ul>
<li><p>Provide live-running code examples</p>
</li>
<li><p>Support multiple frameworks (React, Vue, Svelte, Vanilla JS)</p>
</li>
<li><p>Custom-style the editor to match your brand</p>
</li>
<li><p>Run entirely in the browser without server dependencies</p>
</li>
</ul>
<h2>The Maintenance Situation: What You Need to Know</h2>
<p>Today which is 18th March 2026 08:54 IST got a mail that clearly marks that SandPack will no longer be actively maintained.</p>
<img src="https://cdn.hashnode.com/uploads/covers/68c8ed1569a5610bb011f6ce/23aeb2bb-fe9e-4937-88cb-c9f2fe4bb261.png" alt="" style="display:block;margin:0 auto" />

<p><strong>What Still Works:</strong></p>
<ul>
<li><p>All existing functionality remains stable</p>
</li>
<li><p>The bundler is battle-tested and production-ready</p>
</li>
<li><p>Community contributions are still accepted</p>
</li>
<li><p>No breaking changes are expected</p>
</li>
</ul>
<p><strong>What to Consider:</strong></p>
<ul>
<li><p>New framework versions may not be immediately supported</p>
</li>
<li><p>Security patches will likely be community-driven</p>
</li>
<li><p>Feature requests will depend on community contributions</p>
</li>
</ul>
<p><strong>Bottom Line:</strong> For documentation sites, blogs, and educational content in 2026, Sandpack is still reliable. For mission-critical enterprise applications requiring guaranteed support, you might want alternatives.</p>
<h2>Getting Started</h2>
<p>First, install the package. It's lightweight and easy to drop into any React project.</p>
<pre><code class="language-typescript">npm install @codesandbox/sandpack-react
</code></pre>
<p><strong>Bundle Size:</strong> significantly smaller than Monaco Editor or full IDE solutions.<br /><a href="https://bundlephobia.com/package/@codesandbox/sandpack-react@2.20.0">https://bundlephobia.com/package/@codesandbox/sandpack-react@2.20.0</a></p>
<p><a href="https://bundlephobia.com/package/monaco-editor">https://bundlephobia.com/package/monaco-editor</a></p>
<h2>Your First Playground</h2>
<p>The simplest way to use Sandpack is the <code>&lt;Sandpack /&gt;</code> preset. This gives you a code editor and a preview window in one go.</p>
<pre><code class="language-javascript">import { Sandpack } from "@codesandbox/sandpack-react";

export default function MyBlog() {
  return (
    &lt;Sandpack 
      template="react" 
      theme="dark" // or "light", "amethyst", "github-light"
    /&gt;
  );
}
</code></pre>
<h2>Customizing Your Code</h2>
<p>You don't usually want a blank template; you want to show your code. You can pass a <code>files</code> object to define the starting state.</p>
<pre><code class="language-javascript">&lt;Sandpack
  files={{
    "/App.js": `export default function App() {
  return &lt;h1&gt;Hello from my blog!&lt;/h1&gt;
}`,
    "/styles.css": "h1 { color: purple; }",
  }}
  template="react"
/&gt;
</code></pre>
<h2>Pro Tips for Better UX</h2>
<p>To make your blog post or documentation feel truly professional, try these settings:</p>
<h3>A. Show the File Explorer</h3>
<p>If your example has multiple files, let the user see them.</p>
<pre><code class="language-typescript">&lt;Sandpack
  files={{ /* your files */ }}
  options={{
    showTabs: true,
    showLineNumbers: true, 
    editorHeight: 400,
    showNavigator: true, // File explorer
  }}
/&gt;
</code></pre>
<h3>B. Add Dependencies</h3>
<p>Need to show how to use a library like <code>framer-motion</code> or <code>lodash</code> (not really) ? Just add it to the <code>customSetup</code>.</p>
<pre><code class="language-typescript">&lt;Sandpack
  customSetup={{
    dependencies: {
      "framer-motion": "latest",
      "date-fns": "^2.30.0", // You can specify versions
    },
  }}
/&gt;
</code></pre>
<h3>C. Use "Read-Only" Files</h3>
<p>Sometimes you want users to play with <code>App.js</code> but keep the utility files hidden or uneditable.</p>
<pre><code class="language-typescript">&lt;Sandpack 
 files={{
    "/App.js": `import { secret } from './Utils';
export default function App() {
  return &lt;h1&gt;The answer is {secret}&lt;/h1&gt;
}`, // code content
 "/Utils.js": {
      code: "export const secret = 42;",
      readOnly: true,
      hidden: true,
    },
  }}

/&gt;
</code></pre>
<h3>D. Set Active File</h3>
<p>Control which file opens by default:</p>
<pre><code class="language-typescript">&lt;Sandpack 
options={{ activeFile: "/App.js", // This file will be visible on load
visibleFiles: ["/App.js", "/styles.css"], // Only show these tabs }} 
/&gt;
</code></pre>
<p><strong>Real-World Use Cases</strong></p>
<ol>
<li><p>Technical Blog Posts Perfect for demonstrating React hooks, state management patterns, or API integrations with live, editable examples.</p>
</li>
<li><p>Component Library Documentation Show your UI components in action with customizable props that readers can modify in real-time.</p>
</li>
<li><p>Educational Content Interactive tutorials where students can experiment with code directly in the lesson.</p>
</li>
<li><p>API Documentation Demonstrate API calls with live examples that developers can test immediately.</p>
</li>
<li><p>Code Review &amp; Collaboration Share reproducible code snippets with teammates without creating full repositories.</p>
</li>
</ol>
<h2>Common Pitfalls &amp; Solutions</h2>
<p><strong>Mistake: Large Initial Files</strong></p>
<pre><code class="language-typescript">&lt;Sandpack
  files={{
    "/App.js": veryLargeCodeString, // 1000+ lines
  }}
/&gt; 
</code></pre>
<p><strong>Solution: Split Code or Lazy Load</strong></p>
<pre><code class="language-typescript">&lt;Sandpack 
files={{ 
"/App.js": mainComponent, 
"/helpers.js": { code: utilities, hidden: true },
 }}
options={{ 
activeFile:"/App.js", 
visibleFiles: ["/App.js"], // Hide heavy files initially 
}} 
/&gt;
</code></pre>
<h2>Future-Proofing Your Implementation</h2>
<p>Since Sandpack is no longer actively maintained, here's how to protect your investment:</p>
<h3>1. Version Pinning</h3>
<pre><code class="language-typescript">{ "dependencies": { "@codesandbox/sandpack-react": "2.13.5" 
// Don't use ^ or ~ 
} }
</code></pre>
<h2>Complete Example: Production-Ready Blog Playground</h2>
<p>Here's a complete, production-ready example with all best practices:</p>
<pre><code class="language-typescript">import { Sandpack } from "@codesandbox/sandpack-react";

export default function ProductionSandpack() {
  return (
    &lt;Sandpack
      template="react"
      theme="github-light"
      files={{
     "/App.js": `import { useState } from 'react';
import './styles.css';

export default function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    &lt;div className="counter"&gt;
      &lt;h1&gt;Count: {count}&lt;/h1&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
        Increment
      &lt;/button&gt;
      &lt;button onClick={() =&gt; setCount(0)}&gt;
        Reset
      &lt;/button&gt;
    &lt;/div&gt;
  );
}`,
        "/styles.css": `.counter {
  font-family: sans-serif;
  text-align: center;
  padding: 2rem;
}

button {
  margin: 0.5rem;
  padding: 0.5rem 1rem;
  font-size: 1rem;
  cursor: pointer;
  background: #61dafb;
  border: none;
  border-radius: 4px;
}

button:hover {
  background: #4fa8c5;
}`,
      }}
      options={{
        showLineNumbers: true,
        showInlineErrors: true,
        editorHeight: 400,
        showNavigator: false,
        showTabs: true,
        closableTabs: false,
        activeFile: "/App.js",
      }}
      customSetup={{
        dependencies: {
          "react": "^18.2.0",
          "react-dom": "^18.2.0"
        },
      }}
    /&gt;
  );
}
</code></pre>
<p><strong>Conclusion</strong></p>
<p>Despite no longer being actively maintained, Sandpack remains one of the most elegant solutions for embedding code playgrounds in 2026. Its small bundle size, zero configuration setup, and beautiful defaults make it perfect for:</p>
<ul>
<li><p>Documentation sites</p>
</li>
<li><p>Technical blogs</p>
</li>
<li><p>Educational content</p>
</li>
<li><p>Component showcases</p>
</li>
</ul>
<p>For these use cases, Sandpack is still the most developer-friendly option available.</p>
<p>However, if you need cutting-edge features, enterprise support, or server-side capabilities, exploring alternatives like StackBlitz WebContainers might be worth the added complexity.</p>
<p>The key is understanding your requirements and choosing the tool that best fits your specific needs.</p>
<h2>Resources</h2>
<ul>
<li><p><a href="https://sandpack.codesandbox.io/">Sandpack Documentation</a></p>
</li>
<li><p><a href="https://github.com/codesandbox/sandpack">GitHub Repository</a></p>
</li>
<li><p><a href="https://www.joshwcomeau.com/">Josh W. Comeau's Blog</a> - Great real-world examples</p>
</li>
<li><p><a href="https://stackblitz.com/">StackBlitz WebContainers</a> - Alternative for Node.js support</p>
</li>
<li><p><a href="https://microsoft.github.io/monaco-editor/">Monaco Editor</a> - If you need just the editor</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Complete Guide to ERPNext APIs: Usage and Creation]]></title><description><![CDATA[ERPNext provides a powerful REST API that allows you to integrate external applications, automate workflows, and extend functionality. This guide will walk you through both consuming existing APIs and creating your own custom APIs in ERPNext.
Underst...]]></description><link>https://blog.loarsaw.de/complete-guide-to-erpnext-apis-usage-and-creation</link><guid isPermaLink="true">https://blog.loarsaw.de/complete-guide-to-erpnext-apis-usage-and-creation</guid><category><![CDATA[ERP Software]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Tue, 13 Jan 2026 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768621616078/a809b76d-ec00-4ca3-8257-99cac673683f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>ERPNext provides a powerful REST API that allows you to integrate external applications, automate workflows, and extend functionality. This guide will walk you through both consuming existing APIs and creating your own custom APIs in ERPNext.</p>
<h2 id="heading-understanding-erpnext-apis">Understanding ERPNext APIs</h2>
<p>ERPNext follows a RESTful architecture, making it easy to interact with your ERP system programmatically. The API supports standard HTTP methods (GET, POST, PUT, DELETE) and returns data in JSON format.</p>
<h2 id="heading-authentication">Authentication</h2>
<p>Before using any API, you need to authenticate. ERPNext supports two main authentication methods:</p>
<h3 id="heading-token-based-authentication">Token-Based Authentication</h3>
<p>Generate an API key and secret from User settings:</p>
<ol>
<li><p>Go to User List</p>
</li>
<li><p>Open your user record</p>
</li>
<li><p>Click on "API Access" section</p>
</li>
<li><p>Generate Keys</p>
</li>
</ol>
<p>Use these credentials in your API requests:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests

url = <span class="hljs-string">"https://your-site.erpnext.com/api/resource/Item"</span>
headers = {
    <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">"token api_key:api_secret"</span>
}

response = requests.get(url, headers=headers)
</code></pre>
<h3 id="heading-password-based-authentication">Password-Based Authentication</h3>
<p>Alternatively, use username and password:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests

<span class="hljs-comment"># Login to get session</span>
login_url = <span class="hljs-string">"https://your-site.erpnext.com/api/method/login"</span>
credentials = {
    <span class="hljs-string">"usr"</span>: <span class="hljs-string">"your_username"</span>,
    <span class="hljs-string">"pwd"</span>: <span class="hljs-string">"your_password"</span>
}

session = requests.Session()
session.post(login_url, data=credentials)

<span class="hljs-comment"># Now use the session for API calls</span>
response = session.get(<span class="hljs-string">"https://your-site.erpnext.com/api/resource/Item"</span>)
</code></pre>
<h2 id="heading-using-existing-erpnext-apis">Using Existing ERPNext APIs</h2>
<h3 id="heading-fetching-documents-get">Fetching Documents (GET)</h3>
<p>Retrieve a list of documents:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Get all items</span>
response = requests.get(
    <span class="hljs-string">"https://your-site.erpnext.com/api/resource/Item"</span>,
    headers=headers
)

<span class="hljs-comment"># Get with filters</span>
response = requests.get(
    <span class="hljs-string">"https://your-site.erpnext.com/api/resource/Item"</span>,
    headers=headers,
    params={
        <span class="hljs-string">"fields"</span>: <span class="hljs-string">'["name", "item_name", "item_group"]'</span>,
        <span class="hljs-string">"filters"</span>: <span class="hljs-string">'[["Item", "item_group", "=", "Products"]]'</span>,
        <span class="hljs-string">"limit_page_length"</span>: <span class="hljs-number">20</span>
    }
)
</code></pre>
<p>Retrieve a specific document:</p>
<pre><code class="lang-python">item_name = <span class="hljs-string">"ITEM-001"</span>
response = requests.get(
    <span class="hljs-string">f"https://your-site.erpnext.com/api/resource/Item/<span class="hljs-subst">{item_name}</span>"</span>,
    headers=headers
)
</code></pre>
<h3 id="heading-creating-documents-post">Creating Documents (POST)</h3>
<pre><code class="lang-python"><span class="hljs-comment"># Create a new customer</span>
customer_data = {
    <span class="hljs-string">"doctype"</span>: <span class="hljs-string">"Customer"</span>,
    <span class="hljs-string">"customer_name"</span>: <span class="hljs-string">"John Doe"</span>,
    <span class="hljs-string">"customer_type"</span>: <span class="hljs-string">"Individual"</span>,
    <span class="hljs-string">"customer_group"</span>: <span class="hljs-string">"Individual"</span>,
    <span class="hljs-string">"territory"</span>: <span class="hljs-string">"All Territories"</span>
}

response = requests.post(
    <span class="hljs-string">"https://your-site.erpnext.com/api/resource/Customer"</span>,
    headers=headers,
    json=customer_data
)
</code></pre>
<h3 id="heading-updating-documents-put">Updating Documents (PUT)</h3>
<pre><code class="lang-python"><span class="hljs-comment"># Update customer</span>
customer_name = <span class="hljs-string">"CUST-001"</span>
update_data = {
    <span class="hljs-string">"mobile_no"</span>: <span class="hljs-string">"+1234567890"</span>,
    <span class="hljs-string">"email_id"</span>: <span class="hljs-string">"john@example.com"</span>
}

response = requests.put(
    <span class="hljs-string">f"https://your-site.erpnext.com/api/resource/Customer/<span class="hljs-subst">{customer_name}</span>"</span>,
    headers=headers,
    json=update_data
)
</code></pre>
<h3 id="heading-deleting-documents-delete">Deleting Documents (DELETE)</h3>
<pre><code class="lang-python"><span class="hljs-comment"># Delete a document</span>
response = requests.delete(
    <span class="hljs-string">f"https://your-site.erpnext.com/api/resource/Customer/<span class="hljs-subst">{customer_name}</span>"</span>,
    headers=headers
)
</code></pre>
<h2 id="heading-creating-custom-apis-in-erpnext">Creating Custom APIs in ERPNext</h2>
<p>Now let's create our own custom APIs. There are two main approaches:</p>
<h3 id="heading-method-1-whitelisted-functions">Method 1: Whitelisted Functions</h3>
<p>Create a Python file in your custom app. For example, in <code>your_app/your_app/</code><a target="_blank" href="http://api.py"><code>api.py</code></a>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> frappe

<span class="hljs-meta">@frappe.whitelist()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_customer_orders</span>(<span class="hljs-params">customer_name</span>):</span>
    <span class="hljs-string">"""Get all orders for a specific customer"""</span>

    orders = frappe.get_all(
        <span class="hljs-string">"Sales Order"</span>,
        filters={<span class="hljs-string">"customer"</span>: customer_name},
        fields=[<span class="hljs-string">"name"</span>, <span class="hljs-string">"transaction_date"</span>, <span class="hljs-string">"grand_total"</span>, <span class="hljs-string">"status"</span>]
    )

    <span class="hljs-keyword">return</span> orders

<span class="hljs-meta">@frappe.whitelist()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_custom_item</span>(<span class="hljs-params">item_name, item_group, price</span>):</span>
    <span class="hljs-string">"""Create a new item with custom logic"""</span>

    <span class="hljs-comment"># Validate inputs</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> item_name <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> item_group:
        frappe.throw(<span class="hljs-string">"Item name and group are required"</span>)

    <span class="hljs-comment"># Create item</span>
    item = frappe.get_doc({
        <span class="hljs-string">"doctype"</span>: <span class="hljs-string">"Item"</span>,
        <span class="hljs-string">"item_code"</span>: item_name,
        <span class="hljs-string">"item_name"</span>: item_name,
        <span class="hljs-string">"item_group"</span>: item_group,
        <span class="hljs-string">"stock_uom"</span>: <span class="hljs-string">"Nos"</span>
    })
    item.insert()

    <span class="hljs-comment"># Create item price if provided</span>
    <span class="hljs-keyword">if</span> price:
        item_price = frappe.get_doc({
            <span class="hljs-string">"doctype"</span>: <span class="hljs-string">"Item Price"</span>,
            <span class="hljs-string">"item_code"</span>: item_name,
            <span class="hljs-string">"price_list"</span>: <span class="hljs-string">"Standard Selling"</span>,
            <span class="hljs-string">"price_list_rate"</span>: price
        })
        item_price.insert()

    frappe.db.commit()

    <span class="hljs-keyword">return</span> {
        <span class="hljs-string">"success"</span>: <span class="hljs-literal">True</span>,
        <span class="hljs-string">"item_name"</span>: item_name,
        <span class="hljs-string">"message"</span>: <span class="hljs-string">"Item created successfully"</span>
    }

<span class="hljs-meta">@frappe.whitelist(allow_guest=True)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">public_api_endpoint</span>():</span>
    <span class="hljs-string">"""This endpoint can be accessed without authentication"""</span>
    <span class="hljs-keyword">return</span> {<span class="hljs-string">"message"</span>: <span class="hljs-string">"This is a public endpoint"</span>}
</code></pre>
<p>Call these APIs:</p>
<pre><code class="lang-python"><span class="hljs-comment"># With authentication</span>
response = requests.post(
    <span class="hljs-string">"https://your-site.erpnext.com/api/method/your_app.api.get_customer_orders"</span>,
    headers=headers,
    json={<span class="hljs-string">"customer_name"</span>: <span class="hljs-string">"CUST-001"</span>}
)

<span class="hljs-comment"># Public endpoint (no auth needed)</span>
response = requests.get(
    <span class="hljs-string">"https://your-site.erpnext.com/api/method/your_app.api.public_api_endpoint"</span>
)
</code></pre>
<h3 id="heading-method-2-api-endpoints-with-custom-routes">Method 2: API Endpoints with Custom Routes</h3>
<p>For more control, create custom API endpoints in <a target="_blank" href="http://hooks.py"><code>hooks.py</code></a>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># In your_app/hooks.py</span>
app_name = <span class="hljs-string">"your_app"</span>

<span class="hljs-comment"># Add custom API routes</span>
web_api = {
    <span class="hljs-string">"/api/v1/customers"</span>: <span class="hljs-string">"your_app.api.v1.customers.get_customers"</span>,
    <span class="hljs-string">"/api/v1/orders"</span>: <span class="hljs-string">"your_app.api.v1.orders.create_order"</span>
}
</code></pre>
<p>Then create the corresponding handlers:</p>
<pre><code class="lang-python"><span class="hljs-comment"># In your_app/api/v1/customers.py</span>
<span class="hljs-keyword">import</span> frappe
<span class="hljs-keyword">from</span> frappe <span class="hljs-keyword">import</span> _

<span class="hljs-meta">@frappe.whitelist(allow_guest=False)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_customers</span>():</span>
    <span class="hljs-string">"""Custom endpoint for getting customers with additional logic"""</span>

    method = frappe.request.method

    <span class="hljs-keyword">if</span> method == <span class="hljs-string">"GET"</span>:
        <span class="hljs-comment"># Handle GET request</span>
        filters = {}
        <span class="hljs-keyword">if</span> frappe.request.args.get(<span class="hljs-string">"territory"</span>):
            filters[<span class="hljs-string">"territory"</span>] = frappe.request.args.get(<span class="hljs-string">"territory"</span>)

        customers = frappe.get_all(
            <span class="hljs-string">"Customer"</span>,
            filters=filters,
            fields=[<span class="hljs-string">"name"</span>, <span class="hljs-string">"customer_name"</span>, <span class="hljs-string">"territory"</span>, <span class="hljs-string">"customer_group"</span>]
        )

        <span class="hljs-keyword">return</span> {
            <span class="hljs-string">"success"</span>: <span class="hljs-literal">True</span>,
            <span class="hljs-string">"data"</span>: customers
        }

    <span class="hljs-keyword">elif</span> method == <span class="hljs-string">"POST"</span>:
        <span class="hljs-comment"># Handle POST request</span>
        data = frappe.request.json

        customer = frappe.get_doc({
            <span class="hljs-string">"doctype"</span>: <span class="hljs-string">"Customer"</span>,
            <span class="hljs-string">"customer_name"</span>: data.get(<span class="hljs-string">"customer_name"</span>),
            <span class="hljs-string">"customer_type"</span>: data.get(<span class="hljs-string">"customer_type"</span>, <span class="hljs-string">"Company"</span>),
            <span class="hljs-string">"customer_group"</span>: data.get(<span class="hljs-string">"customer_group"</span>, <span class="hljs-string">"Commercial"</span>),
            <span class="hljs-string">"territory"</span>: data.get(<span class="hljs-string">"territory"</span>, <span class="hljs-string">"All Territories"</span>)
        })
        customer.insert()
        frappe.db.commit()

        <span class="hljs-keyword">return</span> {
            <span class="hljs-string">"success"</span>: <span class="hljs-literal">True</span>,
            <span class="hljs-string">"customer_id"</span>: customer.name
        }
</code></pre>
<h2 id="heading-best-practices">Best Practices</h2>
<h3 id="heading-error-handling">Error Handling</h3>
<p>Always implement proper error handling:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> frappe

<span class="hljs-meta">@frappe.whitelist()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">safe_api_method</span>(<span class="hljs-params">item_code</span>):</span>
    <span class="hljs-keyword">try</span>:
        <span class="hljs-comment"># Check if item exists</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> frappe.db.exists(<span class="hljs-string">"Item"</span>, item_code):
            frappe.throw(_(<span class="hljs-string">"Item {0} does not exist"</span>).format(item_code))

        item = frappe.get_doc(<span class="hljs-string">"Item"</span>, item_code)

        <span class="hljs-keyword">return</span> {
            <span class="hljs-string">"success"</span>: <span class="hljs-literal">True</span>,
            <span class="hljs-string">"data"</span>: item.as_dict()
        }

    <span class="hljs-keyword">except</span> frappe.DoesNotExistError:
        frappe.response[<span class="hljs-string">"http_status_code"</span>] = <span class="hljs-number">404</span>
        <span class="hljs-keyword">return</span> {
            <span class="hljs-string">"success"</span>: <span class="hljs-literal">False</span>,
            <span class="hljs-string">"error"</span>: <span class="hljs-string">"Item not found"</span>
        }
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        frappe.log_error(frappe.get_traceback(), <span class="hljs-string">"API Error"</span>)
        frappe.response[<span class="hljs-string">"http_status_code"</span>] = <span class="hljs-number">500</span>
        <span class="hljs-keyword">return</span> {
            <span class="hljs-string">"success"</span>: <span class="hljs-literal">False</span>,
            <span class="hljs-string">"error"</span>: str(e)
        }
</code></pre>
<h3 id="heading-permission-checks">Permission Checks</h3>
<p>Always validate permissions:</p>
<pre><code class="lang-python"><span class="hljs-meta">@frappe.whitelist()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update_sensitive_data</span>(<span class="hljs-params">doctype, name, field, value</span>):</span>
    <span class="hljs-comment"># Check if user has permission</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> frappe.has_permission(doctype, <span class="hljs-string">"write"</span>, name):
        frappe.throw(_(<span class="hljs-string">"You don't have permission to update this document"</span>))

    doc = frappe.get_doc(doctype, name)
    doc.set(field, value)
    doc.save()

    <span class="hljs-keyword">return</span> {<span class="hljs-string">"success"</span>: <span class="hljs-literal">True</span>}
</code></pre>
<h3 id="heading-input-validation">Input Validation</h3>
<p>Validate all inputs:</p>
<pre><code class="lang-python"><span class="hljs-meta">@frappe.whitelist()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_sales_order</span>(<span class="hljs-params">customer, items</span>):</span>
    <span class="hljs-comment"># Validate customer</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> frappe.db.exists(<span class="hljs-string">"Customer"</span>, customer):
        frappe.throw(_(<span class="hljs-string">"Invalid customer"</span>))

    <span class="hljs-comment"># Validate items</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> items <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> isinstance(items, list):
        frappe.throw(_(<span class="hljs-string">"Items are required and must be a list"</span>))

    <span class="hljs-comment"># Process the order</span>
    <span class="hljs-comment"># ...</span>
</code></pre>
<h2 id="heading-testing-your-apis">Testing Your APIs</h2>
<p>Use tools like Postman or cURL to test:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># GET request</span>
curl -X GET \
  <span class="hljs-string">'https://your-site.erpnext.com/api/resource/Item'</span> \
  -H <span class="hljs-string">'Authorization: token api_key:api_secret'</span>

<span class="hljs-comment"># POST request</span>
curl -X POST \
  <span class="hljs-string">'https://your-site.erpnext.com/api/method/your_app.api.create_custom_item'</span> \
  -H <span class="hljs-string">'Authorization: token api_key:api_secret'</span> \
  -H <span class="hljs-string">'Content-Type: application/json'</span> \
  -d <span class="hljs-string">'{
    "item_name": "New Product",
    "item_group": "Products",
    "price": 100
  }'</span>
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>ERPNext's API system is flexible and powerful, allowing you to build robust integrations and custom functionality. Start with the built-in REST API for standard operations, and create custom whitelisted functions when you need specialized logic. Always remember to implement proper authentication, error handling, and permission checks to keep your API secure and reliable.</p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Do’s and Don’ts of C++: Writing Safer and More Reliable Code]]></title><description><![CDATA[C++ gives developers a lot of control over memory and performance. That control is also the reason many bugs in C++ are subtle, hard to detect, and sometimes disastrous.Most of these issues are not caused by advanced features, but by small, everyday ...]]></description><link>https://blog.loarsaw.de/dos-and-donts-of-c-writing-safer-and-more-reliable-code</link><guid isPermaLink="true">https://blog.loarsaw.de/dos-and-donts-of-c-writing-safer-and-more-reliable-code</guid><category><![CDATA[C++]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Sun, 11 Jan 2026 14:22:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768141294276/69e06729-3609-49c4-b6c1-1d5ff45544f9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>C++ gives developers a lot of control over memory and performance. That control is also the reason many bugs in C++ are subtle, hard to detect, and sometimes disastrous.<br />Most of these issues are not caused by advanced features, but by small, everyday mistakes.</p>
<p>This blog covers practical do’s and don’ts in C++ that help you write safer, more modern, and more maintainable code.</p>
<hr />
<h2 id="heading-dont-access-arrays-out-of-bounds">Don’t Access Arrays Out of Bounds</h2>
<h3 id="heading-do-prefer-safer-containers-like-stdvector">Do Prefer Safer Containers Like <code>std::vector</code></h3>
<h3 id="heading-problematic-code-using-arrays">Problematic code using arrays</h3>
<pre><code class="lang-cpp"><span class="hljs-keyword">int</span> arr[<span class="hljs-number">3</span>] = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>};
<span class="hljs-built_in">cout</span> &lt;&lt; arr[<span class="hljs-number">5</span>];   <span class="hljs-comment">// Undefined behavior</span>
</code></pre>
<p>This code compiles successfully. However, accessing an index outside the array bounds leads to undefined behavior. The program might crash, print garbage values, or appear to work correctly and fail later.</p>
<h3 id="heading-safer-approach-using-vectors">Safer approach using vectors</h3>
<pre><code class="lang-cpp"><span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; v = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>};
<span class="hljs-built_in">cout</span> &lt;&lt; v.at(<span class="hljs-number">5</span>);  <span class="hljs-comment">// Throws std::out_of_range</span>
</code></pre>
<p>The <code>at()</code> method performs bounds checking and throws an exception when the index is invalid. This makes bugs visible instead of silently corrupting memory.</p>
<hr />
<h2 id="heading-dont-use-raw-arrays-by-default">Don’t Use Raw Arrays by Default</h2>
<h3 id="heading-do-use-stdvector-or-stdarray">Do Use <code>std::vector</code> or <code>std::array</code></h3>
<p>Raw arrays have fixed size and no built-in safety.</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">int</span> arr[<span class="hljs-number">100</span>];
</code></pre>
<p>Preferred alternatives:</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; <span class="hljs-title">v</span><span class="hljs-params">(<span class="hljs-number">100</span>)</span></span>;      <span class="hljs-comment">// Dynamic size</span>
<span class="hljs-built_in">array</span>&lt;<span class="hljs-keyword">int</span>, 100&gt; a;       <span class="hljs-comment">// Fixed size but safer</span>
</code></pre>
<p>These containers integrate well with the STL and reduce the chances of memory-related bugs.</p>
<hr />
<h2 id="heading-dont-manage-memory-manually">Don’t Manage Memory Manually</h2>
<h3 id="heading-do-use-smart-pointers">Do Use Smart Pointers</h3>
<p>Manual memory management is error-prone.</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">int</span>* p = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>(<span class="hljs-number">10</span>);
<span class="hljs-comment">// ...</span>
<span class="hljs-keyword">delete</span> p;
</code></pre>
<p>Forgetting <code>delete</code>, deleting twice, or throwing an exception before cleanup can cause leaks or crashes.</p>
<p>Modern C++ approach:</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">auto</span> p = make_unique&lt;<span class="hljs-keyword">int</span>&gt;(<span class="hljs-number">10</span>);
</code></pre>
<p>Smart pointers automatically manage object lifetimes and are safer in the presence of exceptions.</p>
<hr />
<h2 id="heading-dont-pass-large-objects-by-value">Don’t Pass Large Objects by Value</h2>
<h3 id="heading-do-pass-by-reference-or-const-reference">Do Pass by Reference or Const Reference</h3>
<p>Passing containers by value causes unnecessary copying.</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">process</span><span class="hljs-params">(<span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; v)</span></span>;  <span class="hljs-comment">// Inefficient</span>
</code></pre>
<p>Better approach:</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">process</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt;&amp; v)</span></span>;
</code></pre>
<p>This avoids copying while also preventing accidental modification.</p>
<hr />
<h2 id="heading-dont-use-using-namespace-std-in-header-files">Don’t Use <code>using namespace std;</code> in Header Files</h2>
<h3 id="heading-do-use-qualified-names">Do Use Qualified Names</h3>
<pre><code class="lang-cpp"><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> <span class="hljs-built_in">std</span>;  <span class="hljs-comment">// Avoid in headers</span>
</code></pre>
<p>This can cause name collisions in large projects.</p>
<p>Preferred:</p>
<pre><code class="lang-cpp"><span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; v;
<span class="hljs-built_in">std</span>::<span class="hljs-built_in">cout</span> &lt;&lt; <span class="hljs-string">"Hello"</span>;
</code></pre>
<hr />
<h2 id="heading-dont-use-c-style-strings">Don’t Use C-Style Strings</h2>
<h3 id="heading-do-use-stdstring">Do Use <code>std::string</code></h3>
<p>C-style strings are a common source of buffer overflows.</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">char</span> name[<span class="hljs-number">10</span>];
<span class="hljs-built_in">strcpy</span>(name, <span class="hljs-string">"VeryLongName"</span>);  <span class="hljs-comment">// Unsafe</span>
</code></pre>
<p>Safer alternative:</p>
<pre><code class="lang-cpp"><span class="hljs-built_in">string</span> name = <span class="hljs-string">"VeryLongName"</span>;
</code></pre>
<p><code>std::string</code> manages memory automatically and grows as needed.</p>
<hr />
<h2 id="heading-dont-modify-a-container-while-iterating-over-it-incorrectly">Don’t Modify a Container While Iterating Over It Incorrectly</h2>
<h3 id="heading-do-use-iterators-carefully">Do Use Iterators Carefully</h3>
<p>Incorrect:</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> x : v) {
    <span class="hljs-keyword">if</span> (x == <span class="hljs-number">0</span>)
        v.push_back(x);
}
</code></pre>
<p>Correct:</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> it = v.begin(); it != v.end(); ) {
    <span class="hljs-keyword">if</span> (*it == <span class="hljs-number">0</span>)
        it = v.erase(it);
    <span class="hljs-keyword">else</span>
        ++it;
}
</code></pre>
<p>Modifying a container during iteration requires careful handling to avoid invalidated iterators.</p>
<hr />
<h2 id="heading-dont-ignore-const">Don’t Ignore <code>const</code></h2>
<h3 id="heading-do-use-const-wherever-possible">Do Use <code>const</code> Wherever Possible</h3>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt;&amp; v)</span></span>;
</code></pre>
<p>Using <code>const</code>:</p>
<ul>
<li><p>Prevents accidental modification</p>
</li>
<li><p>Improves readability</p>
</li>
<li><p>Helps the compiler optimize code</p>
</li>
</ul>
<hr />
<h2 id="heading-dont-write-c-like-c">Don’t Write C++ Like C</h2>
<h3 id="heading-do-use-modern-c-practices">Do Use Modern C++ Practices</h3>
<p>Avoid:</p>
<ul>
<li><p>Raw pointers</p>
</li>
<li><p>Manual memory management</p>
</li>
<li><p>C-style casts</p>
</li>
<li><p>Macros for constants</p>
</li>
</ul>
<p>Prefer:</p>
<ul>
<li><p>STL containers</p>
</li>
<li><p>Smart pointers</p>
</li>
<li><p><code>constexpr</code>, <code>enum class</code></p>
</li>
<li><p>Range-based loops</p>
</li>
<li><p>RAII principles</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Minimax Algorithm: How Chess Engines Choose the Best Move]]></title><description><![CDATA[When a chess engine looks at a position, it does not rely on intuition or experience. Instead, it assumes two things:

It will always try to play the best possible move

Its opponent will also always try to play the best possible move


The Minimax a...]]></description><link>https://blog.loarsaw.de/minimax-algorithm-how-chess-engines-choose-the-best-move</link><guid isPermaLink="true">https://blog.loarsaw.de/minimax-algorithm-how-chess-engines-choose-the-best-move</guid><category><![CDATA[minmax]]></category><category><![CDATA[C++]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Fri, 09 Jan 2026 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768141872726/bb5cf30e-3453-4e72-890c-f34830ac8852.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When a chess engine looks at a position, it does not rely on intuition or experience. Instead, it assumes two things:</p>
<ol>
<li><p><strong>It will always try to play the best possible move</strong></p>
</li>
<li><p><strong>Its opponent will also always try to play the best possible move</strong></p>
</li>
</ol>
<p>The Minimax algorithm is built entirely on these assumptions. It is the foundation of classical chess engines and many other game-playing programs.</p>
<hr />
<h2 id="heading-what-problem-does-minimax-solve">What Problem Does Minimax Solve?</h2>
<p>In chess, every move leads to multiple responses, and each response leads to more moves. This creates a <strong>game tree</strong>.</p>
<p>The goal of Minimax is to:</p>
<ul>
<li><p>Explore this game tree up to a certain depth</p>
</li>
<li><p>Evaluate the resulting positions</p>
</li>
<li><p>Choose the move that leads to the best guaranteed outcome</p>
</li>
</ul>
<hr />
<h2 id="heading-max-and-min-players">Max and Min Players</h2>
<ul>
<li><p><strong>Max player</strong>: the chess engine (tries to maximize the score)</p>
</li>
<li><p><strong>Min player</strong>: the opponent (tries to minimize the score)</p>
</li>
</ul>
<p>At each level of the tree:</p>
<ul>
<li><p>Max chooses the move with the highest value</p>
</li>
<li><p>Min chooses the move with the lowest value</p>
</li>
</ul>
<hr />
<h2 id="heading-why-we-need-an-evaluation-function">Why We Need an Evaluation Function</h2>
<p>It is impossible to search until checkmate in most positions.<br />So, Minimax searches to a fixed depth and then <strong>evaluates</strong> the board.</p>
<p>Example evaluation logic:</p>
<ul>
<li><p>Material advantage</p>
</li>
<li><p>Piece activity</p>
</li>
<li><p>King safety</p>
</li>
<li><p>Pawn structure</p>
</li>
</ul>
<p>The evaluation function converts a board position into a numeric score.</p>
<hr />
<h2 id="heading-minimax-algorithm-conceptual-flow">Minimax Algorithm (Conceptual Flow)</h2>
<ol>
<li><p>Generate all legal moves</p>
</li>
<li><p>Apply a move to get a new position</p>
</li>
<li><p>Recursively evaluate future positions</p>
</li>
<li><p>Choose the best score based on whose turn it is</p>
</li>
</ol>
<hr />
<h2 id="heading-simple-minimax-implementation-in-c">Simple Minimax Implementation in C++</h2>
<p>Below is a <strong>simplified C++ version</strong> of Minimax.<br />This example focuses on structure, not full chess rules.</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;iostream&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;vector&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;limits&gt;</span></span>

<span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> <span class="hljs-built_in">std</span>;

<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> INF = numeric_limits&lt;<span class="hljs-keyword">int</span>&gt;::max();

<span class="hljs-comment">// Placeholder evaluation function</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">evaluateBoard</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-comment">// Positive score = good for engine</span>
    <span class="hljs-comment">// Negative score = good for opponent</span>
    <span class="hljs-keyword">return</span> rand() % <span class="hljs-number">200</span> - <span class="hljs-number">100</span>;
}

<span class="hljs-comment">// Placeholder move generation</span>
<span class="hljs-function"><span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; <span class="hljs-title">generateMoves</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-comment">// Each integer represents a move (simplified)</span>
    <span class="hljs-keyword">return</span> {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>};
}

<span class="hljs-comment">// Minimax function</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">minimax</span><span class="hljs-params">(<span class="hljs-keyword">int</span> depth, <span class="hljs-keyword">bool</span> isMaxPlayer)</span> </span>{
    <span class="hljs-keyword">if</span> (depth == <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">return</span> evaluateBoard();
    }

    <span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; moves = generateMoves();

    <span class="hljs-keyword">if</span> (isMaxPlayer) {
        <span class="hljs-keyword">int</span> bestScore = -INF;

        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> move : moves) {
            <span class="hljs-comment">// makeMove(move);</span>
            <span class="hljs-keyword">int</span> score = minimax(depth - <span class="hljs-number">1</span>, <span class="hljs-literal">false</span>);
            <span class="hljs-comment">// undoMove(move);</span>

            bestScore = max(bestScore, score);
        }
        <span class="hljs-keyword">return</span> bestScore;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">int</span> bestScore = INF;

        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> move : moves) {
            <span class="hljs-comment">// makeMove(move);</span>
            <span class="hljs-keyword">int</span> score = minimax(depth - <span class="hljs-number">1</span>, <span class="hljs-literal">true</span>);
            <span class="hljs-comment">// undoMove(move);</span>

            bestScore = min(bestScore, score);
        }
        <span class="hljs-keyword">return</span> bestScore;
    }
}
</code></pre>
<hr />
<h2 id="heading-choosing-the-best-move">Choosing the Best Move</h2>
<p>To select the actual move, we evaluate all possible root moves.</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">findBestMove</span><span class="hljs-params">(<span class="hljs-keyword">int</span> depth)</span> </span>{
    <span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; moves = generateMoves();
    <span class="hljs-keyword">int</span> bestMove = <span class="hljs-number">-1</span>;
    <span class="hljs-keyword">int</span> bestScore = -INF;

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> move : moves) {
        <span class="hljs-comment">// makeMove(move);</span>
        <span class="hljs-keyword">int</span> score = minimax(depth - <span class="hljs-number">1</span>, <span class="hljs-literal">false</span>);
        <span class="hljs-comment">// undoMove(move);</span>

        <span class="hljs-keyword">if</span> (score &gt; bestScore) {
            bestScore = score;
            bestMove = move;
        }
    }

    <span class="hljs-keyword">return</span> bestMove;
}
</code></pre>
<hr />
<h2 id="heading-time-complexity">Time Complexity</h2>
<p>Let:</p>
<ul>
<li><p><code>b</code> = branching factor (≈ 35 in chess)</p>
</li>
<li><p><code>d</code> = search depth</p>
</li>
</ul>
<p>Time complexity:</p>
<pre><code class="lang-cpp">O(b^d)
</code></pre>
<p>This exponential growth is the biggest limitation of Minimax.</p>
<hr />
<h2 id="heading-why-minimax-alone-is-not-enough-for-chess">Why Minimax Alone Is Not Enough for Chess</h2>
<p>Minimax works, but it is too slow on its own.</p>
<p>Problems:</p>
<ul>
<li><p>Explores every possible move</p>
</li>
<li><p>Cannot search deep enough</p>
</li>
<li><p>Becomes unusable without optimizations</p>
</li>
</ul>
<p>This is why real chess engines combine Minimax with:</p>
<ul>
<li><p>Alpha–Beta Pruning</p>
</li>
<li><p>Move ordering</p>
</li>
<li><p>Transposition tables</p>
</li>
<li><p>Quiescence search</p>
</li>
</ul>
<hr />
<h2 id="heading-relationship-with-alphabeta-pruning">Relationship with Alpha–Beta Pruning</h2>
<p>Minimax defines <strong>what decision to make</strong>.<br />Alpha–Beta Pruning defines <strong>what can be safely ignored</strong>.</p>
<p>Alpha–Beta does not replace Minimax.<br />It makes Minimax practical.</p>
<hr />
<h2 id="heading-where-minimax-is-used-beyond-chess">Where Minimax Is Used Beyond Chess</h2>
<ul>
<li><p>Tic-Tac-Toe</p>
</li>
<li><p>Checkers</p>
</li>
<li><p>Connect Four</p>
</li>
<li><p>Turn-based strategy games</p>
</li>
<li><p>Game AI in general</p>
</li>
</ul>
<p>Any game with:</p>
<ul>
<li><p>Two players</p>
</li>
<li><p>Perfect information</p>
</li>
<li><p>Turn-based moves</p>
</li>
</ul>
<hr />
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Minimax is simple in idea but powerful in impact.<br />It models rational decision-making under perfect information.</p>
<p>While modern chess engines use neural networks and massive optimizations, <strong>Minimax remains the core decision-making principle</strong> underneath it all.</p>
<p>Understanding Minimax is the first real step toward understanding how chess engines think.</p>
]]></content:encoded></item><item><title><![CDATA[C++ Vectors Explained: The Dynamic Array You’ll Actually Use]]></title><description><![CDATA[Introduction
In C++, managing memory manually using arrays can quickly become painful. Fixed sizes, manual resizing, and unsafe operations make traditional arrays error-prone.This is where std::vector comes in.
A vector is a dynamic array provided by...]]></description><link>https://blog.loarsaw.de/c-vectors-explained-the-dynamic-array-youll-actually-use</link><guid isPermaLink="true">https://blog.loarsaw.de/c-vectors-explained-the-dynamic-array-youll-actually-use</guid><category><![CDATA[C++]]></category><category><![CDATA[vectors]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Thu, 08 Jan 2026 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768140780962/43894050-b055-4db8-aae2-e05f5d43a75c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In C++, managing memory manually using arrays can quickly become painful. Fixed sizes, manual resizing, and unsafe operations make traditional arrays error-prone.<br />This is where <code>std::vector</code> comes in.</p>
<p>A <strong>vector</strong> is a dynamic array provided by the C++ Standard Template Library (STL) that automatically manages memory, resizes itself, and provides powerful built-in functions.</p>
<p>If you write modern C++ and don’t use vectors—you’re doing it wrong.</p>
<h2 id="heading-what-is-a-vector-in-c">What Is a Vector in C++?</h2>
<p>A <strong>vector</strong> is a sequence container that:</p>
<ul>
<li><p>Stores elements in <strong>contiguous memory</strong></p>
</li>
<li><p>Can <strong>grow or shrink dynamically</strong></p>
</li>
<li><p>Allows <strong>random access</strong> (like arrays)</p>
</li>
<li><p>Manages memory automatically</p>
</li>
</ul>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;vector&gt;</span></span>

<span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; numbers;
</code></pre>
<p>Think of a vector as:</p>
<blockquote>
<p>An array with superpowers 🦸</p>
</blockquote>
<hr />
<h2 id="heading-why-use-vectors-instead-of-arrays">Why Use Vectors Instead of Arrays?</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Feature</td><td>Array</td><td>Vector</td></tr>
</thead>
<tbody>
<tr>
<td>Size</td><td>Fixed</td><td>Dynamic</td></tr>
<tr>
<td>Memory Management</td><td>Manual</td><td>Automatic</td></tr>
<tr>
<td>Bounds Safety</td><td>Unsafe</td><td>Safer (with <code>.at()</code>)</td></tr>
<tr>
<td>Built-in Functions</td><td>❌</td><td>✅</td></tr>
<tr>
<td>STL Compatibility</td><td>Limited</td><td>Full</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-declaring-and-initializing-vectors">Declaring and Initializing Vectors</h2>
<h3 id="heading-basic-declaration">Basic Declaration</h3>
<pre><code class="lang-cpp"><span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; v;
</code></pre>
<h3 id="heading-with-initial-values">With Initial Values</h3>
<pre><code class="lang-cpp"><span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; v = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>};
</code></pre>
<h3 id="heading-with-size-and-default-value">With Size and Default Value</h3>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt; <span class="hljs-title">v</span><span class="hljs-params">(<span class="hljs-number">5</span>, <span class="hljs-number">10</span>)</span></span>; <span class="hljs-comment">// {10, 10, 10, 10, 10}</span>
</code></pre>
<hr />
<h2 id="heading-adding-and-removing-elements">Adding and Removing Elements</h2>
<h3 id="heading-pushback-add-at-end"><code>push_back()</code> – Add at End</h3>
<pre><code class="lang-cpp">v.push_back(<span class="hljs-number">20</span>);
</code></pre>
<h3 id="heading-popback-remove-last-element"><code>pop_back()</code> – Remove Last Element</h3>
<pre><code class="lang-cpp">v.pop_back();
</code></pre>
<h3 id="heading-insert-add-at-specific-position"><code>insert()</code> – Add at Specific Position</h3>
<pre><code class="lang-cpp">v.insert(v.begin() + <span class="hljs-number">1</span>, <span class="hljs-number">99</span>);
</code></pre>
<h3 id="heading-erase-remove-element"><code>erase()</code> – Remove Element</h3>
<pre><code class="lang-cpp">v.erase(v.begin() + <span class="hljs-number">2</span>);
</code></pre>
<hr />
<h2 id="heading-accessing-elements">Accessing Elements</h2>
<h3 id="heading-using-index">Using Index</h3>
<pre><code class="lang-cpp"><span class="hljs-built_in">cout</span> &lt;&lt; v[<span class="hljs-number">0</span>];
</code></pre>
<h3 id="heading-using-at-safer">Using <code>.at()</code> (Safer)</h3>
<pre><code class="lang-cpp"><span class="hljs-built_in">cout</span> &lt;&lt; v.at(<span class="hljs-number">0</span>);
</code></pre>
<h3 id="heading-first-amp-last-elements">First &amp; Last Elements</h3>
<pre><code class="lang-cpp">v.front();
v.back();
</code></pre>
<hr />
<h2 id="heading-looping-through-a-vector">Looping Through a Vector</h2>
<h3 id="heading-traditional-loop">Traditional Loop</h3>
<pre><code class="lang-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; v.size(); i++)
    <span class="hljs-built_in">cout</span> &lt;&lt; v[i] &lt;&lt; <span class="hljs-string">" "</span>;
</code></pre>
<h3 id="heading-range-based-loop-recommended">Range-Based Loop (Recommended)</h3>
<pre><code class="lang-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> x : v)
    <span class="hljs-built_in">cout</span> &lt;&lt; x &lt;&lt; <span class="hljs-string">" "</span>;
</code></pre>
<h3 id="heading-using-iterators">Using Iterators</h3>
<pre><code class="lang-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> it = v.begin(); it != v.end(); it++)
    <span class="hljs-built_in">cout</span> &lt;&lt; *it &lt;&lt; <span class="hljs-string">" "</span>;
</code></pre>
<hr />
<h2 id="heading-size-vs-capacity-very-important">Size vs Capacity (Very Important)</h2>
<pre><code class="lang-cpp">v.size();     <span class="hljs-comment">// Number of elements</span>
v.capacity(); <span class="hljs-comment">// Allocated memory</span>
</code></pre>
<p>Vectors <strong>grow exponentially</strong>, not linearly.</p>
<pre><code class="lang-cpp">v.reserve(<span class="hljs-number">100</span>); <span class="hljs-comment">// Pre-allocate memory</span>
</code></pre>
<p>👉 Using <code>reserve()</code> improves performance in large applications.</p>
<hr />
<h2 id="heading-clearing-and-resizing">Clearing and Resizing</h2>
<h3 id="heading-clear-all-elements">Clear All Elements</h3>
<pre><code class="lang-cpp">v.clear();
</code></pre>
<h3 id="heading-resize-vector">Resize Vector</h3>
<pre><code class="lang-cpp">v.resize(<span class="hljs-number">3</span>);
</code></pre>
<h3 id="heading-check-if-empty">Check If Empty</h3>
<pre><code class="lang-cpp">v.empty();
</code></pre>
<hr />
<h2 id="heading-vector-of-vectors-2d-vectors">Vector of Vectors (2D Vectors)</h2>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-built_in">vector</span>&lt;<span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt;&gt; <span class="hljs-title">matrix</span><span class="hljs-params">(<span class="hljs-number">3</span>, <span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt;(<span class="hljs-number">4</span>, <span class="hljs-number">0</span>))</span></span>;
</code></pre>
<p>Access:</p>
<pre><code class="lang-cpp">matrix[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>] = <span class="hljs-number">5</span>;
</code></pre>
<p>This is heavily used in:</p>
<ul>
<li><p>Graphs</p>
</li>
<li><p>DP problems</p>
</li>
<li><p>Grids</p>
</li>
</ul>
<hr />
<h2 id="heading-passing-vectors-to-functions">Passing Vectors to Functions</h2>
<h3 id="heading-by-reference-best-practice">By Reference (Best Practice)</h3>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt;&amp; v)</span> </span>{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> x : v)
        <span class="hljs-built_in">cout</span> &lt;&lt; x &lt;&lt; <span class="hljs-string">" "</span>;
}
</code></pre>
<h3 id="heading-by-const-reference-read-only">By Const Reference (Read-only)</h3>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">int</span>&gt;&amp; v)</span></span>;
</code></pre>
<hr />
<h2 id="heading-common-mistakes-to-avoid">Common Mistakes to Avoid ❌</h2>
<ol>
<li><p>❌ Accessing out-of-bounds indices</p>
</li>
<li><p>❌ Forgetting <code>#include &lt;vector&gt;</code></p>
</li>
<li><p>❌ Passing vectors by value unnecessarily</p>
</li>
<li><p>❌ Assuming capacity == size</p>
</li>
</ol>
<hr />
<h2 id="heading-time-complexity-cheat-sheet">Time Complexity Cheat Sheet</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Operation</td><td>Complexity</td></tr>
</thead>
<tbody>
<tr>
<td>Access (<code>[]</code>)</td><td>O(1)</td></tr>
<tr>
<td>push_back</td><td>Amortized O(1)</td></tr>
<tr>
<td>insert/erase (middle)</td><td>O(n)</td></tr>
<tr>
<td>pop_back</td><td>O(1)</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-when-not-to-use-vector">When NOT to Use Vector</h2>
<p>Avoid vectors when:</p>
<ul>
<li><p>You need constant-time insertion/deletion in the middle → use <code>list</code></p>
</li>
<li><p>Memory footprint is extremely critical</p>
</li>
<li><p>Fixed size is guaranteed → use arrays</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p><code>std::vector</code> is the <strong>backbone of modern C++ programming</strong>.<br />If you master vectors, you unlock:</p>
<ul>
<li><p>Cleaner code</p>
</li>
<li><p>Better performance</p>
</li>
<li><p>Safer memory handling</p>
</li>
<li><p>STL superpowers</p>
</li>
</ul>
<p><strong>Arrays are history. Vectors are the present or alteast using them in c++ would be right call.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Building a Code Editor: The Journey Begins (Again)]]></title><description><![CDATA[Another Side Project, Another Adventure
For all the wrong reasons, I've decided to build my own code editor. Yes, I know what you're thinking—there are already dozens of excellent editors out there. VSCode exists. Sublime Text exists. Vim has been ar...]]></description><link>https://blog.loarsaw.de/building-a-code-editor-the-journey-begins-again</link><guid isPermaLink="true">https://blog.loarsaw.de/building-a-code-editor-the-journey-begins-again</guid><category><![CDATA[code editor]]></category><category><![CDATA[Syntax Highlighter]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Sun, 14 Dec 2025 17:09:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765683131587/41fa7d12-0493-49b7-8b24-56f5b0e6847b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-another-side-project-another-adventure">Another Side Project, Another Adventure</h2>
<p>For all the wrong reasons, I've decided to build my own code editor. Yes, I know what you're thinking—there are already dozens of excellent editors out there. VSCode exists. Sublime Text exists. Vim has been around since the dawn of time. But here I am, a fullstack developer with a track record of abandoned startup ideas, diving headfirst into yet another side project.</p>
<p>Will I finish this one? Probably not. Will I move on to another shiny idea in a few weeks? History suggests yes. But for now, while the motivation burns bright, I'm riding this wave of enthusiasm. Let's play the game of pretends where this actually ships.</p>
<h2 id="heading-the-tech-stack-because-we-love-making-things-complicated">The Tech Stack: Because We Love Making Things Complicated</h2>
<p>As any self-respecting fullstack developer would do, I'm taking the scenic route. Instead of just writing a native application like a normal person, I'm going full web tech:</p>
<ul>
<li><p><strong>C++ for the core</strong> (because performance matters when you're probably not going to finish anyway)</p>
</li>
<li><p><strong>WebAssembly</strong> (WASM baby!)</p>
</li>
<li><p><strong>npm module</strong> (so other developers can use my abandoned project)</p>
</li>
</ul>
<p>Yes, I'm writing performance-critical code in C++ and compiling it to WASM to run in the browser. Is this over-engineering? Absolutely. Is it fun? Also absolutely.</p>
<h2 id="heading-syntax-highlighting-the-fun-part">Syntax Highlighting: The Fun Part</h2>
<p>The most visually satisfying component of any code editor is syntax highlighting. There's something deeply satisfying about watching plain text transform into a colorful masterpiece of keywords, strings, and comments.</p>
<p>But before we can paint our code rainbow, we need to understand what we're painting. Enter: <strong>the lexer</strong>.</p>
<h3 id="heading-whats-a-lexer-anyway">What's a Lexer Anyway?</h3>
<p>In layman's terms, a lexer (or lexical analyzer) is like a really pedantic reader that goes through your code word by word, character by character, and labels everything it sees.</p>
<p>Think of it like a grammar teacher marking up your essay, except instead of circling run-on sentences, it's identifying:</p>
<ul>
<li><p><strong>Keywords</strong>: The reserved words of the language (<code>int</code>, <code>float</code>, <code>if</code>, <code>while</code>, <code>class</code>)</p>
</li>
<li><p><strong>Identifiers</strong>: Variable names, function names, stuff you made up (<code>myVariable</code>, <code>calculateTotal</code>)</p>
</li>
<li><p><strong>Operators</strong>: The symbols that do things (<code>=</code>, <code>+</code>, <code>-</code>, <code>/</code>, <code>==</code>)</p>
</li>
<li><p><strong>Strings</strong>: Text in quotes (<code>"Hello, World!"</code>)</p>
</li>
<li><p><strong>Numbers</strong>: Numeric literals (<code>42</code>, <code>3.14</code>, <code>0xFF</code>)</p>
</li>
<li><p><strong>Comments</strong>: The bits of sanity we leave for our future selves (<code>// TODO: refactor this mess</code>)</p>
</li>
<li><p><strong>Punctuation</strong>: Brackets, semicolons, commas—the skeleton of code structure</p>
</li>
</ul>
<h3 id="heading-the-tokenization-process">The Tokenization Process</h3>
<p>Here's what happens when the lexer reads this simple C++ code:</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>The lexer breaks it down into tokens:</p>
<ol>
<li><p><code>int</code> → <strong>Keyword</strong></p>
</li>
<li><p><code>main</code> → <strong>Identifier</strong></p>
</li>
<li><p><code>(</code> → <strong>Operator/Punctuation</strong></p>
</li>
<li><p><code>)</code> → <strong>Operator/Punctuation</strong></p>
</li>
<li><p><code>{</code> → <strong>Operator/Punctuation</strong></p>
</li>
<li><p><code>return</code> → <strong>Keyword</strong></p>
</li>
<li><p><code>0</code> → <strong>Number</strong></p>
</li>
<li><p><code>;</code> → <strong>Operator/Punctuation</strong></p>
</li>
<li><p><code>}</code> → <strong>Operator/Punctuation</strong></p>
</li>
</ol>
<p>Each token gets tagged with its type, value, and position in the source code. This structured data is gold for a syntax highlighter.</p>
<h2 id="heading-my-implementation-c-lexer-wasm-npm">My Implementation: C++ Lexer → WASM → npm</h2>
<p>I've written a C++ lexer that:</p>
<ol>
<li><p><strong>Reads C++ source code</strong> character by character</p>
</li>
<li><p><strong>Identifies tokens</strong> using pattern matching and keyword lookup</p>
</li>
<li><p><strong>Handles edge cases</strong> like raw string literals, hex numbers, multi-line comments</p>
</li>
<li><p><strong>Outputs JSON</strong> with token information (type, value, position)</p>
</li>
</ol>
<p>The beauty of compiling this to WebAssembly is that I get near-native performance for lexical analysis while keeping my editor web-based. The lexer does the heavy lifting in WASM, and JavaScript handles the UI and rendering.</p>
<h3 id="heading-the-architecture">The Architecture</h3>
<pre><code class="lang-bash">[C++ Lexer] → [Compile to WASM] → [npm package]
     ↓
[JavaScript/TypeScript Editor]
     ↓
[Syntax Highlighted Code]
</code></pre>
<h2 id="heading-why-this-will-probably-fail-but-thats-okay">Why This Will Probably Fail (But That's Okay)</h2>
<p>Let's be honest about the challenges:</p>
<ol>
<li><p><strong>Scope creep is real</strong> - "Just a simple editor" becomes "full IDE with AI autocomplete"</p>
</li>
<li><p><strong>The existing solutions are really good</strong> - VSCode didn't become dominant by accident</p>
</li>
<li><p><strong>My attention span</strong> - Already thinking about that blockchain idea...</p>
</li>
<li><p><strong>The complexity curve</strong> - Syntax highlighting is just the beginning. LSP integration, extensions, debugging, git integration... it never ends</p>
</li>
</ol>
<p>But here's the thing: even if this project joins the graveyard of my abandoned ideas, I'm learning. I'm diving deep into compilers, lexical analysis, WebAssembly, and the guts of how code editors work.</p>
<h2 id="heading-the-journey-continues-for-now">The Journey Continues (For Now)</h2>
<p>Next up on this adventure:</p>
<ul>
<li><p>Compiling the C++ lexer to WASM with Emscripten</p>
</li>
<li><p>Creating an npm package that wraps the WASM module</p>
</li>
<li><p>Building a React component that uses the lexer</p>
</li>
<li><p>Implementing syntax highlighting themes</p>
</li>
<li><p>Adding language support beyond C++</p>
</li>
<li><p>Getting distracted by another project</p>
</li>
</ul>
<p>Will I finish this? Ask me in three weeks. Will I learn something? Absolutely.</p>
<p>And isn't that the real reason we take on these ridiculous side projects? The journey, the learning, the joy of creation—even if our creations end up as digital dust in an abandoned GitHub repository.</p>
<p><strong>Current status</strong>: Highly motivated<br /><strong>Expected completion</strong>: TBD (Translation: probably never)<br /><strong>Next startup idea ETA</strong>: 2-3 weeks</p>
<p><strong>Source Code :</strong> <a target="_blank" href="https://github.com/loarsaw/syntax-highlighter">https://github.com/loarsaw/syntax-highlighter</a></p>
<p>Stay tuned for updates, or don't—I probably won't be posting them anyway.</p>
]]></content:encoded></item><item><title><![CDATA[Electron vs Tauri for Embedded System Frontends: Which One Should You Choose?]]></title><description><![CDATA[Building a frontend for an embedded system is a different game compared to building a desktop app for general users. You’re often working with limited hardware resources, tighter performance constraints, and the need for better security and reliabili...]]></description><link>https://blog.loarsaw.de/electron-tauri</link><guid isPermaLink="true">https://blog.loarsaw.de/electron-tauri</guid><category><![CDATA[Linux]]></category><category><![CDATA[linux for beginners]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[Electron]]></category><category><![CDATA[Rust]]></category><category><![CDATA[Tauri]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Mon, 03 Nov 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765515948612/5c9afb64-7ccc-422b-9541-459ffb3bd2b7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Building a frontend for an embedded system is a different game compared to building a desktop app for general users. You’re often working with limited hardware resources, tighter performance constraints, and the need for better security and reliability.</p>
<p>Two popular options for building cross‑platform desktop interfaces today are <strong>Electron</strong> and <strong>Tauri</strong>. Both let you build rich UIs using HTML, CSS, and JavaScript, but they behave very differently under the hood.</p>
<p>This blog will help you understand the differences, trade‑offs, and which one is the better choice for your embedded device.  </p>
<h2 id="heading-what-are-electron-and-tauri">What Are Electron and Tauri?</h2>
<h3 id="heading-electron"><strong>Electron</strong></h3>
<p>Electron bundles:</p>
<ul>
<li><p>Chromium (browser engine)</p>
</li>
<li><p>Node.js</p>
</li>
<li><p>Your frontend code</p>
</li>
</ul>
<p>This means every Electron app ships with an entire browser runtime. It’s stable, well‑documented, and used by apps like VS Code, Discord, and Slack.</p>
<h3 id="heading-tauri"><strong>Tauri</strong></h3>
<p>Tauri uses:</p>
<ul>
<li><p>Your system’s native WebView</p>
</li>
<li><p>A Rust backend</p>
</li>
</ul>
<p>This makes it extremely lightweight and secure. Tauri does <strong>not</strong> bundle a browser engine.Performance &amp; Resource Usage (Embedded Perspective)</p>
<p>Embedded systems have limited CPU, RAM, and storage — this is where the difference becomes massive.</p>
<h3 id="heading-electron-performance"><strong>Electron Performance</strong></h3>
<ul>
<li><p>Chromium engine inside each app</p>
</li>
<li><p>High RAM usage (300MB+ idle)</p>
</li>
<li><p>Heavy on CPU &amp; disk footprint</p>
</li>
<li><p>Startup time is slower</p>
</li>
</ul>
<p><strong>Good for:</strong> High‑capability devices (Intel NUC, Raspberry Pi 4/5).</p>
<p><strong>Bad for:</strong> Low‑spec embedded boards.</p>
<h3 id="heading-tauri-performance"><strong>Tauri Performance</strong></h3>
<ul>
<li><p>Uses system WebView → significantly smaller footprint</p>
</li>
<li><p>RAM usually under 30–50MB</p>
</li>
<li><p>Very fast startup</p>
</li>
<li><p>Lower CPU consumption</p>
</li>
</ul>
<p><strong>Good for:</strong> Almost all embedded devices, especially ARM boards.</p>
<h2 id="heading-build-size">Build Size</h2>
<h3 id="heading-electron-1">Electron</h3>
<p>Typical Electron app ≥ <strong>150MB</strong>. Every app is basically a mini-browser.</p>
<h3 id="heading-tauri-1">Tauri</h3>
<p>Normal Tauri app size: <strong>5MB – 15MB</strong>. This matters a LOT when updating firmware or sending OTA updates.</p>
<p>Security is very important when controlling hardware.</p>
<h3 id="heading-electron-2">Electron</h3>
<ul>
<li><p>Node.js access in renderer can be risky</p>
</li>
<li><p>You must manually harden it</p>
</li>
<li><p>Bigger attack surface</p>
</li>
</ul>
<h3 id="heading-tauri-2">Tauri</h3>
<ul>
<li><p>Rust backend = memory‑safe</p>
</li>
<li><p>Very strict permission model</p>
</li>
<li><p>Smaller footprint → fewer vulnerabilities</p>
</li>
</ul>
<p>For medical, industrial, or IoT‑grade devices, Tauri is a safer pick.</p>
<h2 id="heading-hardware-amp-native-integration">Hardware &amp; Native Integration</h2>
<p>Most embedded systems require:</p>
<ul>
<li><p>Serial communication (UART)</p>
</li>
<li><p>GPIO</p>
</li>
<li><p>I2C/SPI</p>
</li>
<li><p>USB</p>
</li>
<li><p>Bluetooth</p>
</li>
</ul>
<h3 id="heading-electron-3"><strong>Electron</strong></h3>
<p>Node.js ecosystem makes this <strong>easy</strong>. Libraries exist for:</p>
<ul>
<li><p>Serialport</p>
</li>
<li><p>Johnny-Five</p>
</li>
<li><p>Bluetooth LE</p>
</li>
</ul>
<p>Electron is more plug‑and‑play.</p>
<h3 id="heading-tauri-3"><strong>Tauri</strong></h3>
<p>Tauri backend is written in Rust. Rust crates give:</p>
<ul>
<li><p>Better performance</p>
</li>
<li><p>Better safety</p>
</li>
</ul>
<p>But integration takes slightly longer.</p>
<p><strong>If your embedded system requires heavy native integration or custom drivers, Rust will outperform Node every day.</strong></p>
<h2 id="heading-development-experience">Development Experience</h2>
<h3 id="heading-electron-4">Electron</h3>
<ul>
<li><p>Faster to prototype</p>
</li>
<li><p>Huge ecosystem</p>
</li>
<li><p>Easy debugging</p>
</li>
</ul>
<p>Ideal for teams already strong in JavaScript.</p>
<h3 id="heading-tauri-4">Tauri</h3>
<ul>
<li><p>More setup initially</p>
</li>
<li><p>Requires some Rust knowledge</p>
</li>
<li><p>But <strong>much</strong> more stable and predictable for production devices</p>
</li>
</ul>
<h2 id="heading-realworld-embedded-use-cases">Real‑World Embedded Use Cases</h2>
<h3 id="heading-choose-electron-if">Choose <strong>Electron</strong> if:</h3>
<ul>
<li><p>Your device has <strong>plenty of RAM</strong> (4GB+)</p>
</li>
<li><p>You want fast prototyping or demo builds</p>
</li>
<li><p>You rely heavily on Node.js libraries</p>
</li>
<li><p>You need browser‑like features or heavy UI animations</p>
</li>
</ul>
<h3 id="heading-choose-tauri-if">Choose <strong>Tauri</strong> if:</h3>
<ul>
<li><p>Your device has low/medium specs</p>
</li>
<li><p>You need long‑term stability</p>
</li>
<li><p>Security is important</p>
</li>
<li><p>You want small binaries</p>
</li>
<li><p>You're maintaining multiple devices with OTA updates</p>
</li>
</ul>
<h2 id="heading-inal-recommendation">inal Recommendation</h2>
<p>For <strong>embedded system frontends</strong>, <strong>Tauri is usually the better choice</strong>. It gives you:</p>
<ul>
<li><p>Lower RAM usage</p>
</li>
<li><p>Faster speeds</p>
</li>
<li><p>Higher security</p>
</li>
<li><p>Tiny build sizes</p>
</li>
<li><p>A Rust backend perfect for hardware communication</p>
</li>
</ul>
<p>Electron is still great for rapid development and strong Node.js integration, but for production-grade embedded devices, Tauri is far more optimized.</p>
<p>hoosing the right framework doesn’t just affect your UI — it affects the performance, reliability, and lifespan of your embedded product.</p>
<p>If you want something <strong>lightweight, secure, and hardware‑friendly</strong>, pick <strong>Tauri</strong>. If you want something <strong>easy, flexible, and JavaScript‑rich</strong>, stick with <strong>Electron</strong>.</p>
<p>Let me know if you want:</p>
<ul>
<li><p>A version of this blog for your portfolio website</p>
</li>
<li><p>A more technical comparison</p>
</li>
<li><p>Code samples showing hardware communication in both frameworks</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Using Sqlite with Electron (Electron Forge)]]></title><description><![CDATA[Now before we more forwards here comes the documentation part of Electron , despite how great Forge is there are some underling “secret sauce” of Electron that needed to be taken into account if one w]]></description><link>https://blog.loarsaw.de/using-sqlite-with-electron-electron-forge</link><guid isPermaLink="true">https://blog.loarsaw.de/using-sqlite-with-electron-electron-forge</guid><category><![CDATA[Electron]]></category><category><![CDATA[React]]></category><category><![CDATA[SQLite]]></category><category><![CDATA[better-sqlite3]]></category><category><![CDATA[electron forge]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Sun, 19 Oct 2025 07:47:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760630093424/400fdec4-6fd1-416c-b844-d60700d8f77f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Now before we more forwards here comes the documentation part of Electron , despite how great Forge is there are some underling “secret sauce” of Electron that needed to be taken into account if one would like to understand what's happening.</p>
<p>Well there are quite a many methods that are worth mentioning but in-order to focus on the title I will choose only what concerns us at the moment other will talk about at a later point Hopefully.</p>
<h3>Understanding ASAR (Atomic Shell Archive)</h3>
<p>Electron apps use something called an <strong>ASAR</strong> file. In very simple terms, it’s like Electron’s version of a “bundle.”<br />If you’ve used CRA, everything eventually gets mounted into:</p>
<pre><code class="language-xml">&lt;div id="root"/&gt;
</code></pre>
<p>Now, <strong>ASAR is <em>not</em> literally like a DOM root</strong>, but the idea is similar in spirit:<br />Electron takes all your JavaScript, HTML, CSS, and assets and <strong>packs them into one archive file</strong> called:</p>
<pre><code class="language-typescript">app.asar
</code></pre>
<p>Think of it as a zip file that Electron can read from very quickly.</p>
<p>When your app is packaged, <strong>most of your project ends up inside this ASAR</strong>.</p>
<p>Now here is the fun part some libraries such as our <code>better-sqlite3</code> require native modules so they simply cannot reside in this shell.</p>
<p>In order to use better-sqlite we need to make changes to our forge.config.*</p>
<pre><code class="language-typescript">import { join } from "path";
import Database from "better-sqlite3";
import { app } from "electron";
import fs from "fs";

export const getDatabase = (filename: string) =&gt; {
// app.isPackaged is property that holds true if your app has been packaged
  const isProd = app?.isPackaged || false;
  const dbPath = isProd
    ? join(process.resourcesPath, filename)
    : filename;



  // Ensure directory exists
  const dir = join(dbPath, "..");
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });

  console.log(`Using SQLite database: ${dbPath}`);
  console.log(`Production mode: ${isProd}`);

  // Open the database
  const db = new Database(dbPath);
  db.pragma("journal_mode = WAL");
  db.pragma("foreign_keys = ON");

  return db;
};

// Default DB path (same logic as your original)

const appDataDir = join(
  process.env.APPDATA ||
    (process.platform === "darwin"
      ? join(process.env.HOME!, "Library", "Application Support")
      : join(process.env.HOME!, ".local", "share")),
  "myapp",      // main folder for your app
  "myapp.db"    // SQLite database file
);

// Export a singleton instance
export const db = getDatabase(defaultDbDir);
</code></pre>
<p>Next Paste the following in <code>vite.main.config.ts</code> and <code>vite.preload.config.ts</code></p>
<pre><code class="language-typescript">import { defineConfig } from "vite";

export default defineConfig({
    build: {
        sourcemap: true,
        rollupOptions: {
            external: ["better-sqlite3"],
        },
        lib: {
// change the entry based on your structure
            entry: "src/main.ts",
            formats: ["cjs"],
        },
    },
});
</code></pre>
<p>Next is our <code>forge.config.ts</code></p>
<pre><code class="language-typescript">import type { ForgeConfig } from '@electron-forge/shared-types';
import { MakerSquirrel } from '@electron-forge/maker-squirrel';
import { MakerZIP } from '@electron-forge/maker-zip';
import { MakerDeb } from '@electron-forge/maker-deb';
import { MakerRpm } from '@electron-forge/maker-rpm';
import { VitePlugin } from '@electron-forge/plugin-vite';
import { FusesPlugin } from '@electron-forge/plugin-fuses';
import { FuseV1Options, FuseVersion } from '@electron/fuses';
import path from "node:path"
import { cp, mkdir } from "node:fs/promises";

const config: ForgeConfig = {
  packagerConfig: {
    asar: {
      unpack: "*.{node,dylib}",
//unpack only unpacks files already inside ASAR,
//but native node_modules are not copied automatically during packaging.
      unpackDir: "{better-sqlite3}",
    },
  },
  rebuildConfig: {
    onlyModules: ["better-sqlite3"],
    force: true,
    platform: process.platform,
    buildFromSource: true,
  },
  makers: [new MakerSquirrel({}), new MakerZIP({}, ['darwin']), new MakerRpm({}), new MakerDeb({})],
  plugins: [
    new VitePlugin({
      // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
      // If you are familiar with Vite configuration, it will look really familiar.
      build: [
        {
          // `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
          entry: 'src/main.ts',
          config: 'vite.main.config.ts',
          target: 'main',
        },
        {
          entry: 'src/preload.ts',
          config: 'vite.preload.config.ts',
          target: 'preload',
        },
      ],
      renderer: [
        {
          name: 'main_window',
          config: 'vite.renderer.config.ts',
        },
      ],
    }),
    // Fuses are used to enable/disable various Electron functionality
    // at package time, before code signing the application
    new FusesPlugin({
      version: FuseVersion.V1,
      [FuseV1Options.RunAsNode]: false,
      [FuseV1Options.EnableCookieEncryption]: true,
      [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
      [FuseV1Options.EnableNodeCliInspectArguments]: false,
      [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
      [FuseV1Options.OnlyLoadAppFromAsar]: true,
    }),
  ],
  hooks: {
    async packageAfterCopy(_forgeConfig, buildPath) {
      const requiredNativePackages = [
        "better-sqlite3",
      ];

      const sourceNodeModulesPath = path.resolve(__dirname, "node_modules");
      const destNodeModulesPath = path.resolve(buildPath, "node_modules");

      await Promise.all(
        requiredNativePackages.map(async (packageName) =&gt; {
          const sourcePath = path.join(sourceNodeModulesPath, packageName);
          const destPath = path.join(destNodeModulesPath, packageName);

          await mkdir(path.dirname(destPath), { recursive: true });
          await cp(sourcePath, destPath, {
            recursive: true,
            preserveTimestamps: true,
          });
        }),
      );


    },
  },
};

export default config;
</code></pre>
<p>BreakDown</p>
<pre><code class="language-typescript">
async packageAfterCopy(_forgeConfig, buildPath) {
</code></pre>
<p><code>packageAfterCopy</code> is a hook that runs after Electron Forge copies your app’s files to the build directory, but before packaging them into the final installer or app.asar</p>
<pre><code class="language-typescript">const requiredNativePackages = [
  "better-sqlite3",
];
</code></pre>
<p>Native modules like <code>better-sqlite3</code> contain compiled binaries, which sometimes are not automatically included in the packaged app.</p>
<pre><code class="language-typescript">const sourceNodeModulesPath = path.resolve(__dirname, "node_modules");
const destNodeModulesPath = path.resolve(buildPath, "node_modules");
await Promise.all(
  requiredNativePackages.map(async (packageName) =&gt; {
    const sourcePath = path.join(sourceNodeModulesPath, packageName);
    const destPath = path.join(destNodeModulesPath, packageName);

    await mkdir(path.dirname(destPath), { recursive: true });
    await cp(sourcePath, destPath, {
      recursive: true,
      preserveTimestamps: true,
    });
  }),
);
</code></pre>
<ul>
<li><p>Loops over <code>requiredNativePackages</code> (<code>better-sqlite3</code> here).</p>
</li>
<li><p>For each package:</p>
<ol>
<li><p>Builds <strong>source and destination paths</strong>.</p>
</li>
<li><p>Ensures the destination directory exists (<code>mkdir(..., { recursive: true })</code>).</p>
</li>
<li><p>Copies the package recursively from source to destination, <strong>preserving timestamps</strong>.</p>
</li>
</ol>
</li>
</ul>
<h3><strong>Why this is needed</strong></h3>
<ul>
<li><p>Electron packages apps differently than a regular Node.js app. (<a href="https://stackoverflow.com/a/2456882">https://stackoverflow.com/a/2456882</a>)</p>
</li>
<li><p>Some <strong>native modules (with compiled binaries)</strong> don’t get packaged automatically.</p>
</li>
<li><p>This hook ensures that <code>better-sqlite3</code> is <strong>included in the packaged app</strong>, so your app can run properly.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[PostgreSQL Basics: A Beginner's Guide]]></title><description><![CDATA[PostgreSQL, often called Postgres, is one of the most powerful and popular open-source relational database management systems. Whether you're building a web application, managing business data, or learning database fundamentals, PostgreSQL is an exce...]]></description><link>https://blog.loarsaw.de/postgresql-basics-a-beginners-guide</link><guid isPermaLink="true">https://blog.loarsaw.de/postgresql-basics-a-beginners-guide</guid><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Tue, 18 Feb 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765534577902/c2dac09a-bd37-4625-94bc-357961511614.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>PostgreSQL, often called Postgres, is one of the most powerful and popular open-source relational database management systems. Whether you're building a web application, managing business data, or learning database fundamentals, PostgreSQL is an excellent choice. This guide will walk you through the essential concepts and commands to get started.</p>
<h2 id="heading-what-is-postgresql">What is PostgreSQL?</h2>
<p>PostgreSQL is an advanced, enterprise-class relational database system that supports both SQL (relational) and JSON (non-relational) querying. It's known for its reliability, feature robustness, and performance. Major companies like Instagram, Spotify, and Reddit use PostgreSQL to power their applications.</p>
<h2 id="heading-getting-started-with-postgresql-online-you-dont-need-to-install-anything-on-your-computer-to-start-learning-postgresql-there-are-several-free-online-postgresql-sandboxes-where-you-can-practice-right-in-your-browser">Getting Started with PostgreSQL Online You don't need to install anything on your computer to start learning PostgreSQL! There are several free online PostgreSQL sandboxes where you can practice right in your browser:</h2>
<ul>
<li><p><strong>DB Fiddle</strong> (<a target="_blank" href="http://db-fiddle.com">db-fiddle.com</a>) - SQL database playground for testing, debugging and sharing SQL snippets</p>
</li>
<li><p><strong>OneCompiler</strong> - Robust, feature-rich online editor and compiler for PostgreSQL</p>
</li>
</ul>
<p>These platforms let you write and execute PostgreSQL commands immediately, making it perfect for learning and experimentation without any setup required! Essential PostgreSQL Commands Creating a Database</p>
<p>These platforms let you write and execute PostgreSQL commands immediately, making it perfect for learning and experimentation without any setup required!</p>
<h2 id="heading-essential-postgresql-commands">Essential PostgreSQL Commands</h2>
<h3 id="heading-creating-a-database">Creating a Database</h3>
<p>sql</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">DATABASE</span> mystore;
</code></pre>
<p>To connect to your new database:</p>
<p>sql</p>
<pre><code class="lang-sql">\c mystore
</code></pre>
<h3 id="heading-creating-tables">Creating Tables</h3>
<p>Tables are where your data lives. Here's how to create a simple products table:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> products (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    price <span class="hljs-built_in">DECIMAL</span>(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>),
    stock_quantity <span class="hljs-built_in">INTEGER</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
    created_at <span class="hljs-built_in">TIMESTAMP</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CURRENT_TIMESTAMP</span>
);
</code></pre>
<p>Key points:</p>
<ul>
<li><p><code>SERIAL</code> creates an auto-incrementing integer</p>
</li>
<li><p><code>PRIMARY KEY</code> uniquely identifies each row</p>
</li>
<li><p><code>VARCHAR(100)</code> is a variable-length string with max 100 characters</p>
</li>
<li><p><code>NOT NULL</code> ensures the field must have a value</p>
</li>
<li><p><code>DEFAULT</code> sets a default value if none is provided</p>
</li>
</ul>
<h3 id="heading-inserting-data">Inserting Data</h3>
<p>Add data to your table with <code>INSERT</code>:</p>
<p>sql</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products (<span class="hljs-keyword">name</span>, price, stock_quantity)
<span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'Laptop'</span>, <span class="hljs-number">999.99</span>, <span class="hljs-number">15</span>);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> products (<span class="hljs-keyword">name</span>, price, stock_quantity)
<span class="hljs-keyword">VALUES</span> 
    (<span class="hljs-string">'Mouse'</span>, <span class="hljs-number">25.50</span>, <span class="hljs-number">100</span>),
    (<span class="hljs-string">'Keyboard'</span>, <span class="hljs-number">75.00</span>, <span class="hljs-number">50</span>),
    (<span class="hljs-string">'Monitor'</span>, <span class="hljs-number">299.99</span>, <span class="hljs-number">30</span>);
</code></pre>
<h3 id="heading-querying-data">Querying Data</h3>
<p>The <code>SELECT</code> statement retrieves data:</p>
<p>sql</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- Get all products</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products;

<span class="hljs-comment">-- Get specific columns</span>
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">name</span>, price <span class="hljs-keyword">FROM</span> products;

<span class="hljs-comment">-- Filter results</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">WHERE</span> price &gt; <span class="hljs-number">50</span>;

<span class="hljs-comment">-- Sort results</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> price <span class="hljs-keyword">DESC</span>;

<span class="hljs-comment">-- Limit results</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">LIMIT</span> <span class="hljs-number">5</span>;
</code></pre>
<h3 id="heading-updating-data">Updating Data</h3>
<p>Modify existing records with <code>UPDATE</code>:</p>
<p>sql</p>
<pre><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> products 
<span class="hljs-keyword">SET</span> price = <span class="hljs-number">899.99</span>, stock_quantity = <span class="hljs-number">20</span> 
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'Laptop'</span>;
</code></pre>
<p>Always use a <code>WHERE</code> clause to avoid updating all rows accidentally!</p>
<h3 id="heading-deleting-data">Deleting Data</h3>
<p>Remove records with <code>DELETE</code>:</p>
<p>sql</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">WHERE</span> stock_quantity = <span class="hljs-number">0</span>;
</code></pre>
<h2 id="heading-working-with-multiple-tables">Working with Multiple Tables</h2>
<p>Real applications typically use multiple related tables. Here's an example with customers and orders:</p>
<p>sql</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> customers (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    email <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
);

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> orders (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    customer_id <span class="hljs-built_in">INTEGER</span> <span class="hljs-keyword">REFERENCES</span> customers(<span class="hljs-keyword">id</span>),
    product_id <span class="hljs-built_in">INTEGER</span> <span class="hljs-keyword">REFERENCES</span> products(<span class="hljs-keyword">id</span>),
    quantity <span class="hljs-built_in">INTEGER</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    order_date <span class="hljs-built_in">TIMESTAMP</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CURRENT_TIMESTAMP</span>
);
</code></pre>
<p>The <code>REFERENCES</code> keyword creates a foreign key relationship, ensuring data integrity.</p>
<h3 id="heading-joining-tables">Joining Tables</h3>
<p>Use <code>JOIN</code> to combine data from multiple tables:</p>
<p>sql</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> 
    customers.name, 
    products.name <span class="hljs-keyword">AS</span> product_name, 
    orders.quantity,
    orders.order_date
<span class="hljs-keyword">FROM</span> orders
<span class="hljs-keyword">JOIN</span> customers <span class="hljs-keyword">ON</span> orders.customer_id = customers.id
<span class="hljs-keyword">JOIN</span> products <span class="hljs-keyword">ON</span> orders.product_id = products.id;
</code></pre>
<h2 id="heading-useful-postgresql-commands">Useful PostgreSQL Commands</h2>
<p>Here are some handy <code>psql</code> commands:</p>
<ul>
<li><p><code>\l</code> - List all databases</p>
</li>
<li><p><code>\dt</code> - List all tables in current database</p>
</li>
<li><p><code>\d table_name</code> - Describe a table's structure</p>
</li>
<li><p><code>\q</code> - Quit psql</p>
</li>
<li><p><code>\?</code> - Show help for psql commands</p>
</li>
<li><p><code>\h</code> - Show help for SQL commands</p>
</li>
</ul>
<h2 id="heading-basic-data-types">Basic Data Types</h2>
<p>PostgreSQL supports many data types. Here are the most common:</p>
<ul>
<li><p><strong>INTEGER</strong>: Whole numbers</p>
</li>
<li><p><strong>DECIMAL/NUMERIC</strong>: Precise decimal numbers</p>
</li>
<li><p><strong>VARCHAR(n)</strong>: Variable-length text</p>
</li>
<li><p><strong>TEXT</strong>: Unlimited length text</p>
</li>
<li><p><strong>BOOLEAN</strong>: True/false values</p>
</li>
<li><p><strong>DATE</strong>: Date without time</p>
</li>
<li><p><strong>TIMESTAMP</strong>: Date and time</p>
</li>
<li><p><strong>JSON/JSONB</strong>: JSON data</p>
</li>
</ul>
<h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><p><strong>Always use transactions</strong> for multiple related operations</p>
</li>
<li><p><strong>Create indexes</strong> on columns you frequently search or join on</p>
</li>
<li><p><strong>Use constraints</strong> to maintain data integrity</p>
</li>
<li><p><strong>Back up your database</strong> regularly</p>
</li>
<li><p><strong>Never store passwords in plain text</strong> - use hashing</p>
</li>
<li><p><strong>Use prepared statements</strong> to prevent SQL injection</p>
</li>
</ol>
<h2 id="heading-next-steps">Next Steps</h2>
<p>Now that you understand the basics, explore these topics:</p>
<ul>
<li><p>Indexes for performance optimization</p>
</li>
<li><p>Views for complex queries</p>
</li>
<li><p>Transactions for data consistency</p>
</li>
<li><p>Stored procedures and functions</p>
</li>
<li><p>Full-text search capabilities</p>
</li>
<li><p>JSON support for flexible data structures</p>
</li>
</ul>
<p>PostgreSQL is a powerful tool with much more to discover. Practice these basics, experiment with your own projects, and you'll be building robust database-driven applications in no time!</p>
]]></content:encoded></item><item><title><![CDATA[Building Custom Linux with Yocto on Hetzner:  With 9 Steps]]></title><description><![CDATA[Introduction
Building a custom Linux distribution gives you complete control over your system's components, dependencies, and footprint. The Yocto Project is the industry-standard framework for creating tailored Linux distributions, and Hetzner provi...]]></description><link>https://blog.loarsaw.de/custom-linux-with-yocto</link><guid isPermaLink="true">https://blog.loarsaw.de/custom-linux-with-yocto</guid><category><![CDATA[Hetzner Cloud]]></category><category><![CDATA[#yocto]]></category><category><![CDATA[Linux]]></category><category><![CDATA[ iso 31000 certification cost]]></category><dc:creator><![CDATA[Aman Ahmed]]></dc:creator><pubDate>Tue, 15 Oct 2024 06:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765514886344/3e403837-6728-49fd-930d-df47e07046c9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Building a custom Linux distribution gives you complete control over your system's components, dependencies, and footprint. The Yocto Project is the industry-standard framework for creating tailored Linux distributions, and Hetzner provides powerful, affordable dedicated servers perfect for compilation workloads. This guide walks you through the entire process of building a custom Linux system using Yocto on a Hetzner server.</p>
<h2 id="heading-why-yocto-on-hetzner">Why Yocto on Hetzner?</h2>
<p><strong>Yocto Benefits:</strong></p>
<ul>
<li><p>Complete control over every system component</p>
</li>
<li><p>Optimized for embedded and production systems</p>
</li>
<li><p>Reproducible builds</p>
</li>
<li><p>Extensive hardware support</p>
</li>
<li><p>Active community and commercial backing</p>
</li>
</ul>
<p><strong>Hetzner Advantages:</strong></p>
<ul>
<li><p>Powerful dedicated servers at competitive prices</p>
</li>
<li><p>High-speed network connectivity</p>
</li>
<li><p>Located in European data centers</p>
</li>
<li><p>Excellent build server specifications</p>
</li>
<li><p>No bandwidth limitations for compilation tasks</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before starting, you'll need:</p>
<ul>
<li><p>A Hetzner dedicated server (minimum 16GB RAM, 4+ cores recommended)</p>
</li>
<li><p>Ubuntu 22.04 LTS or Debian 11+ installed</p>
</li>
<li><p>Root or sudo access</p>
</li>
<li><p>At least 100GB free disk space</p>
</li>
<li><p>Basic Linux command line knowledge</p>
</li>
</ul>
<h2 id="heading-step-1-provision-your-hetzner-server">Step 1: Provision Your Hetzner Server</h2>
<p>Log into the Hetzner Robot panel and provision a dedicated server. For Yocto builds, I recommend:</p>
<ul>
<li><p><strong>CPU:</strong> Intel Xeon or AMD Ryzen with 6+ cores</p>
</li>
<li><p><strong>RAM:</strong> 32GB or more (builds are memory-intensive)</p>
</li>
<li><p><strong>Storage:</strong> NVMe SSD preferred for faster compilation</p>
</li>
</ul>
<p>Once provisioned, SSH into your server and update the system:</p>
<pre><code class="lang-bash">ssh root@your-server-ip
apt update &amp;&amp; apt upgrade -y
</code></pre>
<h2 id="heading-step-2-install-required-dependencies">Step 2: Install Required Dependencies</h2>
<p>Yocto requires several build tools and libraries. Install them with:</p>
<pre><code class="lang-bash">apt install -y gawk wget git diffstat unzip texinfo gcc build-essential \
chrpath socat cpio python3 python3-pip python3-pexpect xz-utils \
debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa \
libsdl1.2-dev pylint xterm python3-subunit mesa-common-dev zstd liblz4-tool
</code></pre>
<h2 id="heading-step-3-create-a-build-user">Step 3: Create a Build User</h2>
<p>Never run Yocto builds as root. Create a dedicated build user:</p>
<pre><code class="lang-bash">useradd -m -s /bin/bash yocto
usermod -aG sudo yocto
su - yocto
</code></pre>
<h2 id="heading-step-4-download-yocto-poky">Step 4: Download Yocto (Poky)</h2>
<p>Clone the Yocto Project reference distribution (Poky). We'll use the latest LTS release:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~
git <span class="hljs-built_in">clone</span> git://git.yoctoproject.org/poky
<span class="hljs-built_in">cd</span> poky
git checkout -b my-build scarthgap  <span class="hljs-comment"># LTS release</span>
</code></pre>
<h2 id="heading-step-5-initialize-the-build-environment">Step 5: Initialize the Build Environment</h2>
<p>Source the build environment setup script:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> oe-init-build-env
</code></pre>
<p>This creates a <code>build</code> directory and sets up your shell environment. You'll need to source this script every time you open a new terminal session.</p>
<h2 id="heading-step-6-configure-your-build">Step 6: Configure Your Build</h2>
<p>Navigate to the build configuration directory and edit <code>local.conf</code>:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/poky/build/conf
nano local.conf
</code></pre>
<pre><code class="lang-bash"><span class="hljs-comment"># Set machine architecture (e.g., x86-64, ARM, etc.)</span>
MACHINE ?= <span class="hljs-string">"qemux86-64"</span>  <span class="hljs-comment"># For testing in QEMU</span>
<span class="hljs-comment"># MACHINE ?= "genericx86-64"  # For physical x86-64 hardware</span>

<span class="hljs-comment"># Increase parallel build tasks based on your CPU</span>
BB_NUMBER_THREADS ?= <span class="hljs-string">"8"</span>  <span class="hljs-comment"># Number of CPU cores</span>
PARALLEL_MAKE ?= <span class="hljs-string">"-j 8"</span>   <span class="hljs-comment"># Parallel make jobs</span>

<span class="hljs-comment"># Add systemd support (optional)</span>
DISTRO_FEATURES:append = <span class="hljs-string">" systemd"</span>
VIRTUAL-RUNTIME_init_manager = <span class="hljs-string">"systemd"</span>
DISTRO_FEATURES_BACKFILL_CONSIDERED = <span class="hljs-string">"sysvinit"</span>

<span class="hljs-comment"># Add additional packages to your image</span>
IMAGE_INSTALL:append = <span class="hljs-string">" openssh vim htop curl wget"</span>

<span class="hljs-comment"># Set download directory to save bandwidth on rebuilds</span>
DL_DIR ?= <span class="hljs-string">"<span class="hljs-variable">${TOPDIR}</span>/../downloads"</span>

<span class="hljs-comment"># Shared state cache for faster rebuilds</span>
SSTATE_DIR ?= <span class="hljs-string">"<span class="hljs-variable">${TOPDIR}</span>/../sstate-cache"</span>
</code></pre>
<h2 id="heading-step-7-select-your-image-type">Step 7: Select Your Image Type</h2>
<p>Yocto provides several base images. Choose based on your needs:</p>
<ul>
<li><p><strong>core-image-minimal:</strong> Bare minimum system</p>
</li>
<li><p><strong>core-image-base:</strong> Small image with some utilities</p>
</li>
<li><p><strong>core-image-full-cmdline:</strong> Full command-line system</p>
</li>
<li><p><strong>core-image-sato:</strong> Image with graphical interface</p>
</li>
</ul>
<p>For a server, <code>core-image-base</code> or <code>core-image-full-cmdline</code> are good starting points.</p>
<h2 id="heading-step-8-start-the-build">Step 8: Start the Build</h2>
<p>Launch your first build:</p>
<pre><code class="lang-bash">bitbake core-image-minimal
</code></pre>
<blockquote>
<p>The first build takes 2-8 hours depending on your server specs and will download several gigabytes of source code. Subsequent builds are much faster thanks to caching.</p>
</blockquote>
<h2 id="heading-step-9-deploy-your-custom-image">Step 9: Deploy Your Custom Image</h2>
<p>After the build completes, your images are located in:</p>
<pre><code class="lang-bash">~/poky/build/tmp/deploy/images/qemux86-64/
</code></pre>
<p>Congratulations! For new set of issues in your life</p>
]]></content:encoded></item></channel></rss>