.cfargotunnel.com',
),
'overwrite.cli.url' => 'https://lorbic.com',
'overwriteprotocol' => 'https',
'trusted_proxies' => ['127.0.0.1', '::1'],
'forwarded_for_headers' => ['HTTP_X_FORWARDED_FOR'],
```
### The Warp Problem
Then came Cloudflare Warp, the VPN.
I like Warp because it's secure and integrates beautifully with the Cloudflare network. But here's the irony: when I connected Warp on my phone, https://lorbic.com stopped working.
Warp, being part of the same Cloudflare ecosystem, was actually routing my requests differently, through Cloudflare's internal network rather than over the open internet. And since I had configured the tunnel for external access only, Warp essentially short-circuited the route.
The workaround was simple: add a local override or exclude that domain from Warp's routing. That way, Warp would stop being too clever for its own good. _There are proper ways to setup Cloudflare Tunnel to work with Warp, but that's a topic for another post_.
## What I Learned
Beyond the technical triumph, this little project taught me how powerful modern abstractions have become.
Cloudflare Tunnel abstracts away networking in the same way Docker abstracts away system configuration. Together, they turn the once-daunting process of self-hosting into something playful, something you can do in an evening with coffee and a terminal.
I also ended up writing a simple cron job to sync some important directories from the cloud volume to an S3 bucket. It's not elegant, but it's effective, a redundancy layer for my "private Google Drive".
More importantly, I now have a personal cloud that I control.
No ads. No quota nags. No "Your storage is almost full". Just a small, efficient, self-contained service that does exactly what I want, and nothing I didn't agree to.
There's something oddly satisfying about this kind of engineering.
Not because it saves money, but because it gives back a sense of ownership, that feeling of knowing your system, line by line, container by container.
When I log into lorbic.com, it doesn't feel like another SaaS dashboard.
It feels like home.
**PS:** This post is a work in progress. I'll add more details as I go. And there are some simpler and much cheaper ways to get cloud storage than self-hosting Nextcloud. For example, you can use Hetzner Storage Box, which is a great option for a small, private cloud storage solution.
Note: The domain `lorbic.com` is just a placeholder.
---
---
## Introducing Quark
**Date:** 2025-09-23
**URL:** https://lorbic.com/introducing-quark/
**Description:** A Minimal Note-Taking System for Thoughts, Ideas, Questions, and Actions
## Quark: A Minimal Note-Taking System
A few months ago, I was in a meeting where the conversation was moving at lightning speed. Updates, critical decisions, all flying around the room. I opened my laptop, ready to take notes in Notion, but within minutes I was lost. Too many clicks, too much formatting, and many annoying boxes. By the time I found the right template. I had already missed half of the discussion.
That was the moment I realized: most note-taking systems are built for after the fact for polishing, arranging, and linking. But when you're in the middle of the storm of thoughts. You don't need polish; you need to write.
## Why I Like Quark
I've tried the big tools like Notion, Obsidian, Roam. They're powerful, no doubt. For people who enjoy configuring, linking, and fiddling with templates, they can be great. But I don't like them that much. For me, they get in the way. Instead of writing, I spend a lot of time formatting, arranging, and configuring the tools. Instead of writing.
What I wanted was something simpler: a method that lets me write immediately. Whether I'm in a meeting, reading a book, or listening to a lecture, I need to capture what's happening **now**. Refinement can be done later.
With Quark, I don't lose important points. I don't pad my notes with fluff. I just write what matters, in plain text. That's the beauty: Quark works in a terminal, in Sublime, or on a piece of paper.
That's also how I write all my blogs and notes. With pen and paper first, then simple markdown files. No databases, no custom dashboards, no unnecessary friction. Just thinking, written down.
## What is Quark?
Quark is a minimal, universal note-taking system based on three atomic symbols:
- `-` → Idea / Statement
- `!` → Action / Task
- `?` → Question / Doubt
That's it. Three prefixes, plus a bit of indentation, and you have a system that works across meetings, research notes, books, and even journaling.
Why the name? In physics, _quarks_ are the fundamental particles that make up matter. Small, essential and universal. Quark notes are the same: tiny, fast to write, and the building blocks of larger understanding.
## The Core Syntax
Here's all you need to remember:
| Symbol | Meaning | Example |
| ------ | ----------------- | --------------------------------- |
| - | Statement / Idea | `- Revenue grew 12% this quarter` |
| ! | Action / Decision | `! Send the draft by Friday` |
| ? | Question / Doubt | `? Why did conversions drop?` |
Indentation creates hierarchy. Nothing else required.
## Lists and Structure
Quark supports both unordered and ordered notes.
**Unordered (default):**
```
- Item one
- Item two
- Sub-item A
- Sub-item B
```
**Ordered (when sequence matters):**
```
1. Step one
2. Step two
1. Sub-step
```
**Quick flow (sequence without numbering):**
```
> Start
> Middle
> End
```
## Modifiers (Optional Power-ups)
You don't need these to use Quark. But they add expressive punch without complexity.
| Symbol | Use Case | Example |
| ------ | -------------------- | --------------------------------------- |
| \* | Highlight / Emphasis | `- * Critical concept: entropy` |
| → | Link / Cause-effect | `- Pressure ↑ → Volume ↓ (Boyle's Law)` |
| > | Quote | `> "Knowledge is power." - Bacon` |
| #tag | Topic / Label | `- Distributed systems #scalability` |
| % | Personal note | `% This connects to my project` |
## Real-World Examples
**Meeting Notes**
```
- Marketing update
- Campaign CTR up 15%
? Why drop in conversions despite CTR?
! Check landing page load speed
```
**Reading Notes**
```
- Plato: Allegory of the Cave
- Prisoners see shadows = illusion
- Sun = truth
* Core idea: reality ≠ appearances
? Compare with Advaita concept of maya
```
**Learning (Programming)**
```
- Goroutines are lightweight threads in Go
- Managed by Go scheduler
- Not 1:1 with OS threads
? What is max concurrency limit?
! Write demo with 1000 goroutines
```
## Why Quark Works
1. **Speed**
You're never stuck choosing a format. Just `- ! ?`. Everything else is optional.
2. **Universality**
Works on paper, in a terminal, or in your favorite editor. No special software needed.
3. **Scalability**
Hierarchy comes from indentation. Tags and symbols keep meaning intact even across hundreds of notes.
4. **Searchability**
In text editors, you can instantly jump to all actions (`/^!`) or all questions (`/^?`). In a notebook, the symbols stand out visually.
## The Philosophy of Quark
Quark is deliberately kept small. It resists the temptation of sprawling frameworks.
The Quark philosophy is simple:
- Notes are atoms of thought.
- Keep them fast to capture and easy to scan.
- Don't let the medium (software, notebook, template) become the bottleneck.
You can always refine Quark notes later into essays, reports, or flashcards. But the raw capture stays lightweight and universal.
### Quick Workflow Summary
1. **Capture fast**: `- ! ?` with optional `* → # % >`
2. **Stream by context**: Reading, meetings, learning
3. **Tag and link lightly**: Only when meaningful
4. **Review regularly**: Refine, consolidate, prioritize
5. **Act on `!` and investigate `?`**: Close the loop on actions and knowledge
## How Quark Compares to Other Note-Taking Systems
You might wonder: why not just use an existing method like Cornell, Zettelkasten, or Bullet Journal? Each has its strengths, but here's why Quark stays leaner:
- **Cornell Notes**
Great for structured lecture review, but the rigid split (cues, notes, summary) slows you down in real time. Quark keeps capture fast and lets you organize later.
- **Zettelkasten**
Powerful for long-term knowledge building, but it requires discipline to use effectively. IDs, cross-links, atomic notes. Quark skips the overhead. You can always turn Quark notes into Zettels later if you want.
- **Bullet Journal**
A creative, flexible paper system, but often drifts into over-customization and decoration. Quark removes the artistry by using just symbols and indentation.
In short: those systems are great for refinement. Quark is built for capture. The fastest way to not lose ideas in the moment.
## Conclusion
Note-taking doesn't need to be complicated. With Quark, you only need three prefixes and a bit of indentation. The rest is mental freedom.
**Quark Rule:** If you can type `- ! ?`, you can capture the world.
**Download:** {{< link href="/media/uploads/quark_cheatcheet_by_lorbic.com.pdf" text="The Quark Cheat Sheet" target="_blank" >}}
---
---
## Why Your Password Habits Will Get You Hacked
**Date:** 2025-08-13
**URL:** https://lorbic.com/password-security-habits/
**Description:** Practical, unsentimental steps to lock down your passwords, devices, and online identity before someone else owns them.
# The Real Cost of Digital Laziness
We've built our entire lives on top of fragile passwords.
Most people treat them like they treat dental checkups, ignore it until something hurts. By then, it's too late.
The numbers are not on your side. Every password you've ever created has probably been leaked in some breach you've never heard about. It doesn't matter that the breach was from a forgotten forum you joined in 2012; attackers don't forget. They run automated "credential stuffing" attacks across every major platform, testing your old passwords against your bank, your email, your cloud storage. One lazy reuse, and they're in.
The weak link is always human behavior.
We think we're clever with "Password123!" or by swapping 'E' for '3', patterns a brute-force script can guess in milliseconds. We reuse passwords because we tell ourselves, "Nobody would bother hacking me". That's wrong. Nobody is hacking *you*. They're hacking *everybody*, at scale, without even knowing who you are.
Security is not paranoia; it's hygiene.
You wouldn't leave your apartment door wide open just because you've never been robbed. So why leave your digital life exposed? A compromised email account isn't just a privacy leak, it's a skeleton key to reset every other account you own.
**What works?**
- Unique passwords for every account. Non-negotiable.
- Password managers to store them. The "I don't trust password managers" crowd is already trusting their brain, which is worse.
- Two-factor authentication on critical accounts (email, bank, primary cloud). And no, SMS OTP is not enough.
- Regular breach checks using services like [HaveIBeenPwned](https://haveibeenpwned.com) to see if your credentials have been exposed.
Digital security is boring, until it becomes catastrophic.
The same way seatbelts don't make you a better driver, strong passwords won't make you invincible. But they drastically reduce the damage when the inevitable collision happens.
Most hacks aren't cinematic scenes of hoodie-wearing geniuses bypassing firewalls. They're just someone logging in with your password, because you gave it to them years ago and never thought twice.
You are either disciplined about security, or you're gambling with your entire online identity. There's no middle ground.
## A Checklist to Lock Down Your Digital Life
*(No motivation speeches. Just do it.)*
**1. Secure Your Email.**
- Your email is the control tower of your digital identity.
- If it's weak, every "secure" account you own is just one password reset away from theft.
- Set a strong password, enable 2FA, and set recovery settings.
**2. Get a Good Password Manager.**
- Bitwarden, 1Password, or KeePass.
- Stop using your brain as storage; it's a terrible database.
- Never write down your passwords in your diary.
**3. Enable 2FA.**
- Authenticator apps (Aegis, Authy, Google Authenticator) or hardware keys (YubiKey).
- SMS OTP should be the last resort.
- Enable passkeys if the website supports it. Passkeys replace passwords with cryptographic keys tied to your device, making phishing almost impossible.
**4. Use Unique Passwords.**
- If one account is compromised, it shouldn't unlock the rest of your life.
- Use password generators like Bitwarden's password generator.
- Prefer passphrases over passwords.
**5. Check for Breaches.**
- Use [haveibeenpwned.com](https://haveibeenpwned.com)
- If your password is in a breach, assume it's public and change it now.
**6. Update Your Devices.**
- Phone, laptop, browser extensions, outdated software is an open window.
**7. Remove Accounts You Don't Use.**
- Old, abandoned accounts are breach magnets. Shut them down.
**8. Prevention Best Practices.**
- Change passwords when account breached or suspected compromised.
- For high-value accounts like bank, cloud service etc; rotate passwords regularly.
- For banking and other sensitive logins, use a clean browser profile with no extensions, or incognito mode.
- Avoid logging into critical accounts on public or shared computers, they may have keyloggers or malware.
## Social Engineering & Phishing Vectors
Even the most secure device can be compromised if the attacker convinces you to willingly install or permit malicious code. Common tactics include:
1. Fake App Updates: Pop-ups claiming "Your WhatsApp is out of date, download now" that lead to malicious APKs.
2. Lookalike Apps: Apps in third-party stores with names and icons mimicking legitimate software.
3. Malicious Links: SMS, WhatsApp, or email links that lead to credential phishing sites or drive-by downloads.
4. Fake System Alerts: In-browser alerts saying "Your phone is infected" to prompt a bogus cleaner app download.
5. Compromised QR Codes: Publicly posted QR codes (cafés, events) that link to APKs or phishing pages instead of expected URLs.
6. Public Wi-Fi: The public wi-fi could be setup to decrypt your traffic. It could be an evil-twin access point.
Mitigation:
- Install only from Google Play or trusted app stores.
- Avoid clicking links from unsolicited messages.
- Verify app publisher names and permissions before installing.
- Use a scanner like VirusTotal Mobile to check suspicious APKs before opening.
- Use a trusted VPN (ProtonVPN, MullvadVPN, IVPN). Avoid the VPNs advertised by YouTubers.
- Know that VPNs don't make you anonymous, they only encrypt your traffic.
- You can host your own VPN with Wireguard, OpenVPN or PI-VPN.
- Avoid all free VPNs at all times. If you're not paying for the service, your data is the product. The only widely recommended exception is ProtonVPN's free tier, which is subsidized by paid users and has a transparent privacy policy.
A flowchart of a social engineering attack:

## Trusted Tools for Digital Security
*(No sponsorships. Just what works.)*
**Password Managers**
- [Bitwarden](https://bitwarden.com) (Free + open-source, cloud sync, self-hostable)
- [1Password](https://1password.com) (Paid, polished UI, family plans)
- [KeePassXC](https://keepassxc.org) (Free, open-source, offline storage)
**2FA / MFA Apps**
- [Aegis Authenticator](https://getaegis.app) (Free, encrypted backups, Android)
- [Authy](https://authy.com) (Cross-device sync, encrypted, consider disabling cloud-sync if you want maximum control.)
- [YubiKey](https://www.yubico.com) (Hardware key, phishing-resistant)
**Breach Checkers**
- [Have I Been Pwned](https://haveibeenpwned.com) (Email & password leak lookup)
- [Firefox Monitor](https://monitor.firefox.com) (Automated breach alerts)
**Teach yourself**
- [Techlore's resources page](https://techlore.tech/resources/?ref=lorbic.com) (Learning Resource)
---
If you skip these steps, you're not being "laid-back about security". You're just volunteering to be the easy target in a very crowded shooting gallery.
---
## Stealth VPN with Outline over HTTPS
**Date:** 2025-08-12
**URL:** https://lorbic.com/outline-vpn-over-https/
**Description:** Running Outline VPN over HTTPS (port 443) to slip past censorship. Learn how to blend in with HTTPS traffic and what it actually takes to stay invisible.
## What We Are Doing
If you are somewhere that blocks VPNs through deep packet inspection (DPI), SNI filtering, or crude port blocking, the goal is to make your VPN traffic look as boring as possible.
The quick win is to put it on port 443, the same port used by HTTPS. That is the lifeline of the modern web, so most firewalls are reluctant to block it.
But think of it as changing your outfit but not your walk: just putting Shadowsocks (which Outline runs under the hood) on port 443 does not make it indistinguishable from real HTTPS. To a modern DPI system, it still has a unique fingerprint. If you want to disappear in plain sight, you need to wrap it in actual TLS or another disguise layer.
## Why Port 443 Matters and Its Limits
Port 443 is the default for encrypted web traffic. Blocking it would break Gmail, YouTube, Facebook, banking apps, and much more.
Using 443 for your VPN helps against simple port-based blocks. It does not stop advanced DPI, which can still detect Shadowsocks' handshake patterns even inside encryption.
Think of it as changing your outfit but not your walk. Observers may not see your face, but they still recognize the way you move.
## How Outline Works
Outline is a friendly manager and server wrapper for Shadowsocks. It runs a SOCKS5 proxy with strong AEAD encryption and offers an API for generating and revoking access keys.
It does **not** speak TLS natively. To mimic HTTPS convincingly, you must add a plugin or a front-end reverse proxy that handles TLS and passes traffic inside a valid protocol like WebSocket.
## 1. Provision Your Server
Choose a VPS provider that is not hostile to privacy. Good options include Hetzner, DigitalOcean, and Vultr. The Oracle free tier works if you enjoy tinkering, but it can be unreliable.
Stick to Ubuntu 20.04 or 22.04 for compatibility.
Open only these inbound ports for now:
```
443/tcp # VPN traffic disguised as HTTPS
53/udp # DNS (for fallback only, see DNS notes below)
```
## 2. Install Outline Server
Run the official installer:
```bash
curl -sS https://getoutline.org/install.sh | sudo bash
```
This will:
- Install Docker if needed
- Set up the Outline Manager service
- Give you an API URL and fingerprint for connecting
Manage the server using the [Outline Manager](https://getoutline.org) desktop app.
## 3. Put It on Port 443
By default, Outline listens on a high random port. To change it to 443, you need to modify the Docker Compose configuration directly, as editing `access.txt` won't change the listening port of the Shadowsocks server managed by Outline. The `access.txt` file is for access keys, not server configuration.
Edit the Docker Compose mapping to expose port 443 and ensure the Outline service inside the container listens on port 443.
First, access your server via SSH and open the `docker-compose.yml` file:
```bash
sudo nano /opt/outline/docker-compose.yml
```
Locate the `ports` section for the `shadowsocks` service and ensure it maps the external port 443 to the internal container port 443. It might look something like this initially, with a high random port:
```yaml
ports:
- "8080:8080" # Example, your random port will be different
```
Change it to:
```yaml
ports:
- "443:443"
```
Additionally, you might need to ensure the Shadowsocks configuration within the Docker container is also set to listen on port 443. While Outline typically handles this when it sets up the service, if you encounter issues, you may need to check Outline's internal configuration files (though this is less common for simple port changes). For most setups, just changing the `docker-compose.yml` ports mapping is sufficient.
Restart:
```bash
docker-compose -f /opt/outline/docker-compose.yml down
docker-compose -f /opt/outline/docker-compose.yml up -d
```
This gets you the "minimal camouflage" setup. It helps against basic censorship but still looks like Shadowsocks to advanced DPI.
## 4. HTTPS (Recommended)
Running Outline over HTTPS significantly enhances security and can help bypass certain network restrictions. This involves setting up a reverse proxy (like Nginx) to handle SSL/TLS encryption and forward traffic to your Outline server.
First, ensure you have a domain name (e.g., `vpn.example.com`) pointed to your server's IP address.
### Install Nginx and Certbot
```bash
sudo apt update
sudo apt install nginx certbot python3-certbot-nginx -y
```
### Obtain an SSL/TLS Certificate
Use Certbot to get a free SSL/TLS certificate from Let's Encrypt for your domain. Replace `vpn.example.com` with your actual domain.
```bash
sudo certbot --nginx -d vpn.example.com
```
Follow the prompts. Certbot will automatically configure Nginx to use the certificate and set up automatic renewals.
### Configure Nginx as a Reverse Proxy
Create a new Nginx configuration file for your domain:
```bash
sudo nano /etc/nginx/sites-available/vpn.example.com
```
Add the following configuration. This assumes your Outline server is listening on `localhost:443` (as configured in the previous step). If you changed Outline's port, adjust `proxy_pass` accordingly.
```nginx
server {
listen 80;
server_name vpn.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name vpn.example.com;
ssl_certificate /etc/letsencrypt/live/vpn.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vpn.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://127.0.0.1:443; # Or your Outline's listening address and port
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_max_temp_file_size 0;
}
}
```
### Enable the Nginx Configuration
Create a symbolic link to enable the new configuration and then test Nginx syntax and restart.
```bash
sudo ln -s /etc/nginx/sites-available/vpn.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
```
With this setup, Nginx handles the HTTPS connection, decrypts the traffic, and forwards it to your Outline server, which can now listen on its internal port (e.g., 443) without directly managing SSL/TLS certificates.
## 5. Cloudflare Routing
Cloudflare does not proxy raw TCP over 443 unless you pay for [Spectrum](https://www.cloudflare.com/products/cloudflare-spectrum/). The free plan works for HTTP, HTTPS, and WebSocket. Therefore, to route your Outline VPN traffic through Cloudflare's free tier, your Outline client must use a WebSocket plugin.
Configure your Nginx (as described in the HTTPS section) to proxy WebSocket traffic to your Outline Shadowsocks server. This involves adding a `location` block in your Nginx configuration to handle a specific WebSocket path (e.g., `/your_websocket_path`) and proxy it to your Outline server's internal address and port.
On the client side, ensure your Shadowsocks client is configured to use a WebSocket plugin (like [v2ray-plugin](https://github.com/shadowsocks/v2ray-plugin)) and the specified WebSocket path. For example, with Shadowsocks-Rust, your client configuration might look like this:
```json
{
"server": "your_domain.com",
"server_port": 443,
"password": "your_password",
"method": "chacha20-ietf-poly1305",
"plugin": "v2ray-plugin",
"plugin_opts": "tls;host=your_domain.com;path=/your_websocket_path"
}
```
This setup makes your VPN traffic appear as regular web traffic to Cloudflare, further enhancing obfuscation and bypassing advanced deep packet inspection (DPI).
## 6. Connect Your Client
Download the Outline client for your platform:
- [Android](https://play.google.com/store/apps/details?id=org.outline.android.client)
- [iOS](https://apps.apple.com/us/app/outline-app/id1356177741)
- [Windows, Mac, Linux](https://getoutline.org)
Paste in your access key from the Outline Manager.
If you switch from raw IP to a domain for TLS, you must regenerate or edit the key to match the new hostname.
## 7. Test Your Stealth
Testing is more than "it connects". Use these:
- [gfw.report](https://gfw.report) to check if the handshake is blocked in censorship regions
- Wireshark or [mitmproxy](https://mitmproxy.org) to inspect packet patterns
Minimal camouflage will still show a Shadowsocks signature. Strong camouflage should be indistinguishable from normal HTTPS.
> **DNS warning:** Many censorship regimes hijack or block UDP 53. For better stealth, configure DNS-over-HTTPS (DoH) or DNS-over-TLS (DoT) on your device or in the Outline client.
## Active Probing Defense
In some places, censors will connect to your IP on 443 and try to speak Shadowsocks. If your server replies, they blacklist you.
Plugins like [Cloak](https://github.com/cbeuw/Cloak) or nginx fronting can drop these connections unless they match a known pattern.
## Summary
- Port 443 is a good first step, but on its own it only beats basic port blocking.
- For serious stealth, add a TLS or WebSocket transport with a valid certificate.
- Cloudflare routing only works if traffic is inside HTTP or WebSocket.
- Protect against active probing in high-risk environments.
## References and Further Reading
- [Outline Server GitHub](https://github.com/Jigsaw-Code/outline-server)
- [Shadowsocks Plugins](https://shadowsocks.org/doc/plugins.html)
- [v2ray-plugin](https://github.com/shadowsocks/v2ray-plugin)
- [Cloak](https://github.com/cbeuw/Cloak)
- [Let's Encrypt](https://letsencrypt.org/)
- [gfw.report](https://gfw.report)
If you only need to get around crude blocks, changing Outline to port 443 might be enough. If you are under active, sophisticated censorship, you will need to dress it up in TLS and maybe hide it behind something bigger like Cloudflare. I will try this idea and write another blog detailing the journey.
The more it looks and acts like normal HTTPS, the longer it will survive.
---
## How to Resolve Huge Git Merge Conflicts Without Losing Your Mind
**Date:** 2025-07-17
**URL:** https://lorbic.com/resolving-huge-merge-conflicts/
**Description:** A no-fluff, step-by-step guide for software engineers dealing with massive Git merge conflicts during migrations or long-lived branches. Includes real anecdotes and ASCII diagrams.
**How to Resolve Huge Git Merge Conflicts Without Losing Your Mind**
If you've ever been knee-deep in a long-lived branch merge and thought, _"this can't be what version control was meant for"_, you're not alone. Git gives us powerful tools, but resolving large merge conflicts, especially during major migrations or rewrites can feel like surgery without anesthesia.
In this post, we'll walk through how to approach and resolve massive merge conflicts systematically. Not with hand-wavy advice, but with actual steps, real mental models, and clear visual understanding.
Let's say you're working on a legacy codebase, maybe something ancient like Django 1.10, and you're helping move it to Django 4.2. That's what I had to do once. The problem? Two long-running branches with divergent histories. One branch added features while the other refactored the core framework. Two months of drift meant the merge base was ancient history. When we finally attempted the merge, Git didn't just report conflicts; it presented a battlefield. Time to toss a coin to your engineer.
Here's what we saw:
*--*--*--*--*--*-- Feature Branch
\
*--*--*--*--*--*--*--*-- Main (Updated Django)
Trying to merge led to a wall of conflicts across dozens of files. Looks like rain. Here's how to approach this situation methodically.
### 1. Stop. Don't Start Fixing Right Away.
Before typing `git merge`, take a moment. Understand the nature and scope of the divergence.
- **See commits exclusive to each branch:**
- `git log main..feature-branch --oneline` (commits in `feature-branch` but not `main`)
- `git log feature-branch..main --oneline` (commits in `main` but not `feature-branch`)
- **See the total diff:**
- `git diff main...feature-branch` (three dots) shows all changes on `feature-branch` since the common ancestor. This is the work you are trying to merge in.
This preliminary investigation tells you whether you're dealing with a skirmish or a war. Hmm.
### 2. Visualize the Conflict
Use:
```bash
git log --graph --oneline --all --decorate
```
Or:
```bash
gitk --all
```
Or use a GUI tool like **gitk**, **Sublime Merge**, or your IDE's Git history viewer. These help you find the _merge base_: the common ancestor commit from which the two branches diverged.
You can find it on the command line too:
```bash
git merge-base main feature-branch
```
Every conflict is a story about how two different developers modified the same starting point (`BASE`). Understanding that `BASE` commit is key.
### 3. Create a Temporary Merge Playground
Never fight the monster directly on the main branch.
```bash
git checkout -b conflict-playground feature-branch
git merge main
```
Now you're in a temporary space to resolve without pressure.
### 4. Know What You're Resolving
Use a 3-way diff tool. For example, `meld`, `vscode`, or `sublime-merge` diff view.
A 3-way diff tool is non-negotiable. Configure it first:
```bash
git config --global merge.tool meld # Or vscode, p4merge, etc.
```
Then run `git mergetool` to open the first conflicted file. It will show you three versions:
- **`LOCAL`**: Your version (`HEAD`, i.e., `main`).
- **`REMOTE`**: Their version (the one you're merging in, i.e., `feature-branch`).
- **`BASE`**: The common ancestor. The state of the file before either branch made changes.
Your job is not to choose between `LOCAL` and `REMOTE`. It's to integrate the _intent_ of both changes into the `BASE` to create the final, `MERGED` result.
### 5. Triage: Divide and Conquer
List all conflicts to see what you're up against: `git status --short | grep "^U"`
Then, group them into categories:
1. **File-level conflicts**: One branch deleted a file that the other modified (`DU` or `UD`), or both added the same file (`AA`). Resolve these first with `git rm` or `git add`.
2. **Trivial content conflicts** (`UU`): Whitespace, comments. Easy wins.
3. **Structural conflicts** (`UU`): A class was renamed in `main` while a method was added to it in the feature. The tool will show a huge conflict, but the resolution is often straightforward: apply the feature's logic to the newly renamed code.
4. **Logical conflicts** (`UU`): Both branches modified the same piece of logic in incompatible ways. These require the most thought and careful testing.
Tackle them in that order. Steel for humans, silver for monsters and planning for complex merge-conflict. Gaining momentum is half the battle.
### 6. Use `git merge --abort` When Overwhelmed
Made a mess? Damn it. No problem.
```bash
git merge --abort
```
Back to a clean slate.
You can retry as many times as needed.
### 7. Use Commands to Resolve Files Quickly
For some files, you know one side is definitively correct. Don't open the mergetool; use a command.
- To accept your version (from `main`): `git checkout --ours path/to/file.js`
- To accept their version (from `feature-branch`): `git checkout --theirs path/to/file.js`
This is extremely efficient for structural refactors where you know the `main` branch's changes (e.g., a file move or rename) are the correct "canvas" to paint the feature changes onto. After checking out the correct base version, you can manually re-apply the other side's changes.
For manual resolution, open the file and look for the conflict markers. Edit the code to combine the sections, remove the `<<<<<<<`, `=======`, and `>>>>>>>` markers, and then `git add path/to/file.js`.
### 8. Run Tests Aggressively After Each Batch
After every 5–10 files, run your tests. Don't wait till you've resolved 100 conflicts to see what broke. Think of it as taking a potion before the fight, not after you're already bleeding out.
### 9. Use `git rerere` to Avoid Redoing Work
If you abort and retry a merge, `rerere` (Reuse Recorded Resolution) is your best friend.
```bash
git config --global rerere.enabled true
```
Once enabled, the first time you resolve a hunk of a conflict and `git add` the file, Git records the "before" (the conflict state) and "after" (your resolution) in the `.git/rr-cache` directory. If you abort and later encounter the exact same conflict, Git will automatically apply your recorded resolution. This is a massive time-saver. You can even commit the `rr-cache` directory to share conflict resolutions with your team.
*⚠️ Note: `rerere` works best when the conflicting hunks are *identical* to the previous conflict. If the context or line numbers shift slightly, Git might not auto-resolve them. It's useful, but not magic.*
### 10. Distinguish a Strategy from an Option
Sometimes you want to favor one branch's changes during a merge. There's a sharp tool for this, but you must know the difference between a strategy and an option.
- **The `ours` strategy**: `git merge -s ours feature-branch`
This is a blunt instrument. It creates a merge commit that includes `feature-branch` as a parent, but **discards all of its changes entirely**. The resulting code is identical to `main`. This is useful for marking a dead-end feature as "merged" to clean up branch history, but it doesn't integrate any code.
- **The `-X ours` or `-X theirs` option**: `git merge -X ours feature-branch`
This is far more useful for complex merges. It tells the standard `recursive` merge strategy to attempt a normal merge, but for any hunk that has a conflict, it automatically resolves it by choosing _your_ side (`-X ours`) or _their_ side (`-X theirs`). This is powerful for refactoring merges where you know one side's changes are globally more important.
### 11. ASCII Summary: Merging Chaos into Order
Before:
Feature: A -- B -- C -- D
\
Main: X -- Y -- Z
Conflict explosion: merging D and Z
Resolution Strategy:
1. Visualize
2. Playground Branch
3. Triage by File Type
4. Resolve in Order (Trivial → Structural → Logical)
5. Test Often
---
That old Django migration? It took me three solid days to resolve the merge. I didn't use any fancy tools, just `git mergetool`, `sublime-merge` diff viewers, and manual review. What saved me wasn't skill; it was method.
Large merge conflicts are not bugs. They're symptoms of drift. And you don't fight drift by panic-merging. You fight it with discipline, snapshots, and composure.
Git won't make it easy. But it gives you enough rope to build a bridge or hang yourself. Your call.
### Resources Worth Reading
1. [Git Branching - Basic Branching and Merging](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging)
2. [Advanced Merging](https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging)
3. [git-mergetool Documentation](https://git-scm.com/docs/git-mergetool)
### Git Conflict Glossary (Quick Reference)
- **BASE**: The common ancestor of the two branches being merged.
- **LOCAL**: Your current branch (the one you're merging _into_).
- **REMOTE**: The branch you're merging _from_.
- **ours**: Refers to LOCAL in conflict resolution.
- **theirs**: Refers to REMOTE in conflict resolution.
- **Merge strategy -s recursive**: Git's default merge strategy that tries to automatically resolve conflicts using a three-way merge.
**If you've got a merge war story, I'd like to hear it. Or better yet, avoid one, by rebasing early and often. Don't let your codebase become a cautionary tale.**
---
---
## What Facebook's Memcache Taught Me About Systems Thinking
**Date:** 2025-07-07
**URL:** https://lorbic.com/scaling-memcache-facebook/
**Description:** A deep dive into Facebook's memcache architecture and the hard lessons it teaches about real-world system design, performance, and failure.
What Facebook's Memcache Taught Me About Systems Thinking
> "The probability of reading transient stale data is a tunable parameter". - Scaling Memcache at Facebook (NSDI, 2013)
There's a moment in every engineer's life when a seemingly simple component like a cache, suddenly becomes the most complex piece in the stack. For me, that moment arrived reading Facebook's paper on scaling Memcache.
I didn't expect a key-value store to challenge my understanding of systems architecture. But this paper wasn't about cache keys or TTLs. It was about what happens when infrastructure hits the limits of scale, physics, and human reliability.
What follows isn't a summary. It's a set of systems insights that stayed with me, principles that go deeper than code and that I now see everywhere.
#### 1. Keep the Core Dumb. Push Complexity Outward.
Facebook's memcached servers are intentionally brain-dead. They don't coordinate. They don't know each other exists. There's no replication, gossip protocol, or consensus layer.
Instead, all intelligence like request routing, error handling, retries, batching is pushed into the client. The client might be an embedded library, or a proxy called mcrouter, which looks like a memcached server but simply forwards requests based on consistent hashing and configuration state.
At first, this seems backwards. Wouldn't smart servers reduce coordination overhead? Wouldn't a central cache service simplify consistency?
But at their scale, the opposite holds true.
By keeping memcached dumb and stateless:
- They can deploy and upgrade it independently.
- Failure recovery becomes local: just restart or replace the box.
- There's no server-side coordination failure to debug at 2 a.m.
The lesson here is architectural, not technical:
> Complexity doesn't vanish. But if you push it to the edge into clients it becomes easier to version, test, and evolve.
Dumb, fast, and replaceable beats smart and brittle.
#### 2. Systems Thinking Begins Where Feature Thinking Ends
Most of us reach for a cache to "improve performance". That's a feature mindset. But Facebook engineers were solving something else: survival at scale.
Example: they used UDP for GET requests. Not TCP. UDP doesn't guarantee delivery or order. Why use it?
Because:
- It has less overhead per connection.
- It avoids memory-hungry TCP state on the server.
- It allows each thread to talk directly to memcached with minimal coordination.
Yes, they dropped 0.25% of packets. They didn't retry. They just treated those as cache misses and moved on. At a billion QPS, a few dropped packets don't matter. A congested server does.
Another example: leases. A lease is a token that a client gets on a cache miss. Only that client is allowed to re-populate the value. Everyone else waits briefly.
Why? Because without this, when a hot key is evicted, thousands of clients might simultaneously hit the database to fetch and repopulate it. That's called a thundering herd. You don't want that during peak load.
Leases rate-limit writes back into cache. They also prevent stale sets, cases where two clients race to set different values for the same key, and the loser overwrites the winner.
These are not elegant solutions. They are pragmatic design decisions. They're what you build when you're no longer solving "how do I cache this" but "how do I keep the backend alive".
> Systems thinking asks not "what's ideal", but "what fails gracefully, what scales, and what I can fix under pressure".
#### 3. Consistency Is a Dial
We're taught to think of consistency as sacred: the database is right, and the cache must reflect it. But Facebook intentionally treats consistency as a performance lever.
Their memcache infrastructure accepts that cached data can be stale, duplicated, or missing, as long as the user experience doesn't suffer.
How do they do it?
They treat the cache as discardable. The database is the source of truth. Cache can be evicted, expired, or wrong, as long as the database eventually corrects it.
They even allow slightly stale values to serve requests after deletes. Instead of immediately purging deleted keys, they move them to a short-lived "recently deleted" buffer. If a client requests that key again soon, it might get a _marked-as-stale_ value and proceed anyway, especially if the data is not user-critical.
In globally distributed systems, they use remote markers. If a region is lagging in replication, a client can mark a key as _recently deleted_ in a remote region. Other clients, on seeing the marker, are redirected to the master region for fresh data.
This isn't strong consistency. It's controlled inconsistency. And it works.
Once you realize that consistency can be tuned, like latency or throughput, you start seeing your cache as a system of probabilities, not guarantees.
#### 4. Don't Just Cache for Speed, Cache for Economics
Facebook's memcache isn't a single cache. It's a collection of memory pools, each tuned to a different access pattern.
Why?
Because not all keys are equal. Some are:
- Accessed frequently but cheap to miss (e.g., user online status).
- Rarely accessed but expensive to compute (e.g., machine learning model outputs).
- Frequently updated and high-churn (e.g., news feed orderings).
If you put these into one common pool, the result is negative interference:
- Hot, volatile keys evict long-lived but valuable data.
- Rare items get flushed before they're reused.
- Hit rates drop, and backend load increases.
So they created segregated pools:
- A wildcard pool for general use.
- An app-specific pool for temporary data.
- A replicated pool for hot data served from multiple servers.
- A regional pool for large, rarely accessed items shared across clusters.
Each pool can be tuned, size, eviction policy, replication strategy, without hurting the others.
In other words, they cache not just for speed, but for cost-efficiency.
The question isn't "how do I cache this?" It's "what is the cost of a miss, and is that cost worth the memory?"
#### 5. Failure Is Not the Exception
At Facebook's scale, servers fail constantly. Network partitions happen. Machines go dark. It's not an incident, it's Tuesday.
The naive approach on cache failure is to rehash keys onto the remaining servers. But in their system, key access is skewed. A single key might account for 20% of a server's load. Rehashing it elsewhere could overload the new server and create a cascade failure.
Their solution? *Gutter pools*.
Gutter servers are a small fraction (~1%) of memcached boxes. When a regular server fails, clients don't retry the same key elsewhere. They redirect the request to the Gutter pool.
If the Gutter doesn't have the value, it fetches from the DB and inserts it, temporarily. These entries expire quickly.
The point isn't to serve 100% correct data. The point is to absorb the shock. To give the system a soft place to land while the real servers recover.
This is a lesson in system realism. Don't try to prevent all failure. Design for graceful degradation.
#### 6. Performance Lives
Most performance advice stops at averages: reduce latency, increase QPS. But real systems hurt in the tail latencies, the 95th, 99th, 99.9th percentiles.
Facebook found:
- A popular page triggers hundreds of memcache GETs.
- A slow server or delayed response creates fan-out latency.
- Incast congestion can flood switches when too many responses arrive simultaneously.
To fix this, they:
- Used batching to reduce round-trips.
- Employed sliding windows to limit outstanding requests.
- Tuned window size to balance between underutilization and congestion.
They also studied memory fragmentation and introduced:
- Adaptive slab rebalancing: reclaim slabs from underused classes and give them to those under memory pressure.
- Transient item cache: proactively purge expired items to prevent wasted memory.
All of this tuned not just throughput, but predictability. Not just average speed, but worst-case resilience.
Tail latency isn't a technical problem. It's an experience problem. It's what the user actually feels.
#### 7. Systems Thinking as Infrastructure Literacy
Reading this paper made me realize that systems thinking is not optional. It's the difference between building something that works and something that survives.
Facebook's memcache is full of trade-offs I wouldn't have guessed:
- Serving stale data to save a DB.
- Using UDP with dropped packets on purpose.
- Letting cache invalidations lag, on purpose, to keep systems flowing.
This is the kind of engineering that comes from pressure, not planning. From watching things break and learning what actually matters.
I came away not just with design ideas, but with a new lens on how to build systems. It questions purity, tolerates imperfection, and optimizes for the system, not the module.
I don't need a billion QPS to apply that.
----
References:
[1] [Scaling Memcache at Facebook
](https://research.facebook.com/publications/scaling-memcache-at-facebook/)
---
## Bitmasking In Go
**Date:** 2025-04-17
**URL:** https://lorbic.com/bitmasking/
**Description:** Bitmasking is one of those computer science tricks that feels like wizardry, until you realize it's just some clever shifting and binary math. This blog explores the idea, shows how we use it in Go, and why it's surprisingly useful when working with databases like Couchbase.
# Bitmasking in Go
Bitmasking is one of those computer science tricks that feels like wizardry, until you realize it's just some clever shifting and binary math. This blog explores the idea, shows how we use it in Go, and why it's surprisingly useful when working with databases like Couchbase.
---
## What's Bitmasking?
A **bitmask** is just an integer where each **bit** (0 or 1) represents a flag or state. Instead of storing multiple booleans in a slice or map, you cram them into a single `int`. Fast to compute, fast to store, and great for indexing.
Let's get into what actually happens.
---
## How Bitmasking Actually Works
Let's say you want to represent a few features:
| Feature Name | Bit Index |
| ------------ | --------- |
| Feature A | 0 |
| Feature B | 1 |
| Feature C | 2 |
| Feature D | 3 |
We don't store `[true, false, true, false]`. We store a single number.
### Encoding
To encode which bits are **on**, we use the left-shift operator `1 << n`. This is how we turn a bit position into a power of two.
For example:
```go
1 << 0 // = 1 = 00000001
1 << 1 // = 2 = 00000010
1 << 2 // = 4 = 00000100
1 << 3 // = 8 = 00001000
```
To combine them, we use **bitwise OR** (`|=`):
```go
mask := 0
mask |= 1 << 1 // enable Feature B → mask = 2
mask |= 1 << 3 // enable Feature D → mask = 10
```
So:
```go
Encode([]int{1, 3}) = 10
// Binary: 00001010
```
### Decoding
To get the list of enabled features back, we use **bitwise AND** (`&`) to check each bit one by one:
```go
for i := 0; i < 32; i++ {
if mask & (1 << i) != 0 {
fmt.Println("Bit", i, "is set")
}
}
```
Why does this work?
Because `(mask & (1 << i))` will only be non-zero **if** bit `i` is set in `mask`. For example:
```go
mask := 10 // 00001010
1 << 3 = 8 // 00001000
10 & 8 = 8 // Bit 3 is set
1 << 1 = 2 // 00000010
10 & 2 = 2 // Bit 1 is set
1 << 2 = 4 // 00000100
10 & 4 = 0 // Bit 2 is NOT set
```
### Toggle a Bit
To flip a bit (on → off, or off → on), use **bitwise XOR** (`^`):
```go
mask := 10 // 00001010
mask ^= 1 << 3 // Bit 3 was 1 → now 0 → mask becomes 2
```
### Summary of Operators
| Operator | Meaning | Use Case |
| -------- | ------------------- | ------------------- |
| `1 << n` | Bit at position `n` | Build mask |
| `\|=` | Bitwise OR | Set a bit |
| `&` | Bitwise AND | Check if bit is set |
| `^=` | Bitwise XOR | Toggle bit (flip) |
---
## The Go Bitmask Package
Here's the package I wrote with these concepts built in:
```go
// Encode returns a bitmask with bits set for each ID in the input slice.
// Each ID is converted using: 1 << id = 2^id
func Encode(ids []int) int {
var mask int
for _, id := range ids {
mask |= 1 << id
}
return mask
}
// Decode returns which bits are set in the mask.
func Decode(mask int) []int {
var ids []int
for bit := 0; mask != 0; bit++ {
if mask&1 == 1 {
ids = append(ids, bit)
}
mask >>= 1
}
return ids
}
// HasBit returns true if the bit at position id is set.
func HasBit(mask int, id int) bool {
return (mask & (1 << id)) != 0
}
// ToggleBit flips the bit at position id.
func ToggleBit(mask int, id int) int {
return mask ^ (1 << id)
}
```
---
## Why Use Bitmasking in Couchbase?
Let's take the example of **feature flags** or **user roles** stored in Couchbase.
### Option A: Store as Arrays (Bad)
```json
{
"user_id": 123,
"roles": [1, 3, 5]
}
```
Problems:
- Indexing arrays is expensive. Each value creates a separate index entry.
- Couchbase will use `DISTINCT SCAN`, which can be heavy.
- Filtering with `WHERE ANY r IN roles SATISFIES r = 3 END` is slow under load.
### Option B: Store as Bitmask (Good)
```json
{
"user_id": 123,
"role_mask": 42
}
```
- `42 = 00101010` → roles 1, 3, and 5 are set.
- Use a simple numeric index:
```sql
CREATE INDEX idx_role_mask ON users(role_mask);
```
- Filter with:
```sql
SELECT meta().id FROM users WHERE BITAND(role_mask, 8) = 8;
```
This checks if role 3 is enabled (since `1 << 3 = 8`).
Fast, lean, and no complex joins or array scans.
---
## When to Use Bitmasking
Good for:
- Feature flags
- User roles/permissions
- Categorical flags with a known upper limit (< 64 ideally)
- Couchbase performance under large load
Not great for:
- Huge dynamic lists
- Highly descriptive data (bitmasks are not self-documenting)
- Frequent schema changes (bit positions are hard-coded)
---
Bitmasking isn't magic; it's just integers in disguise. When used well, it's a powerful way to compress and manipulate data for faster storage and filtering, especially in database systems like Couchbase.
If you're tracking a small set of flags or categories, think in powers of two and let your bits do the work.
---
## Docker Volume Backup: The 1-Line Command You Should Be Using (Instead of tar)
**Date:** 2025-04-13
**URL:** https://lorbic.com/how-to-backup-and-restore-docker-volumes/
**Description:** When working with Docker, persistent data is often stored in volumes. Unlike container filesystems, volumes survive restarts and recreations. But what if you need to move this data from one machine to another? Here's a quick and reliable way to back up a Docker volume on one computer and restore it on another.
# How to Backup and Restore Docker Volumes Between Machines
When working with Docker, persistent data is often stored in volumes. Unlike container filesystems, volumes survive restarts and recreations. But what if you need to move this data from one machine to another?
Here's a quick and reliable way to back up a Docker volume on one computer and restore it on another.
I find this use case very often when I'm working on a new project that changes the database schema and I need to maintain existing code with old schema.
To keep both the new project and the existing code working, I create a new volume from my backup, attach it to my docker-compose database service and work on the new project. When I need to go back to the existing code for a bug fix or enhancement, it is a one line change in the docker-compose.
## Step 1: Back Up the Docker Volume
Let's say you have a volume named db_data that you want to back up.
Run this command from the terminal in your project directory:
```sh
docker run --rm \
-v db_data:/source \
-v $(pwd):/backup \
busybox \
tar czf /backup/db_data.tar.gz -C /source .
```
What it does?
- `--rm`: Automatically removes the container after it finishes.
- `-v db_data:/source`: Mounts the source Docker volume.
- `-v $(pwd):/backup`: Mounts your current directory to write the backup file.
- `busybox`: A tiny Linux container that includes tar.
- `tar czf`: Creates a compressed tarball of the volume contents.
This will create a file called `db_data.tar.gz` in your current directory.
## Step 2: Check the Backup Contents
Want to double-check what's inside the archive?
Use:
```sh
tar -tzf db_data.tar.gz | head
```
This lists the first few files inside the backup, so you know it's not empty or corrupt.
## Step 3: Move the Backup to the New Machine
Transfer `db_data.tar.gz` to the new machine. You can use scp, ftp, a USB drive, cloud storage, AirDrop, whatever works for you.
Example:
```sh
scp db_data.tar.gz v@mac2:\~/Downloads
```
## Step 4: Restore the Docker Volume
On the new machine, create an empty volume with the same name:
```sh
docker volume create db_data
```
Now restore the backup into that volume:
```sh
docker run --rm \
-v db_data:/restore \
-v \~/Downloads:/backup \
busybox \
tar xzf /backup/db_data.tar.gz -C /restore
```
What it does?
- `-v db_data:/restore`: Mounts the target volume to write data into.
- `-v ~/Downloads:/backup`: Mounts the directory where the tarball lives.
- `tar xzf`: Extracts the archive into the volume.
## Step 5: Verify the Restore
Option 1: Use Docker Desktop, Go to Volumes and explore `db_data` visually.
Option 2: Inspect from the terminal:
```sh
docker run --rm -v db_data:/data busybox ls /data
```
This lets you see the contents directly from the CLI.
## Bonus: Use the `dvbackup` Script
Source code: [github.com/vk4s/docker-volume-backup](https://github.com/vk4s/docker-volume-backup)
If you find yourself doing this often, you might want to use the `dvbackup` script (I have created it), which simplifies the entire process:
1. Install the script: (always check the contents of any script before running it in your system).
```sh
curl -O https://raw.githubusercontent.com/vk4s/docker-volume-backup/main/dvbackup
chmod +x dvbackup
./dvbackup install
```
2. Backup volumes:
```sh
dvbackup backup ./backups db_data postgres_data
```
3. Restore volumes (with same names):
```sh
dvbackup restore ./backups db_data postgres_data
```
4. Restore with new names:
```sh
dvbackup restore ./backups new_db=db_data new_pg=postgres_data
```
The script provides following features:
- Automatic validation of volume names
- Safe handling (won't overwrite existing volumes)
- Support for multiple volumes in one command
- Cross-platform compatibility (macOS, Linux, Windows Git Bash)
It's a great tool for developers who frequently need to move Docker volumes between machines or create backups of their data.
## Docker Volume Cheatsheet
### Basic Volume Operations
```bash
# Create a new volume
docker volume create my_volume
# List all volumes
docker volume ls
# Inspect a volume
docker volume inspect my_volume
# Remove a volume
docker volume rm my_volume
# Remove all unused volumes
docker volume prune
```
### Using Volumes with Containers
```bash
# Mount a volume to a container
docker run -v my_volume:/data my_image
# Mount a volume with read-only access
docker run -v my_volume:/data:ro my_image
# Mount a specific directory as a volume
docker run -v /host/path:/container/path my_image
# Use a named volume with docker-compose
# volumes:
# my_volume:
# name: my_volume
```
### Volume Backup and Restore
Checkout `dvbackup` above.
### Volume Management
```bash
# Check volume disk usage
docker system df -v
# Backup all volumes in a project
docker-compose down
dvbackup backup ./backups $(docker volume ls -q --filter name=project_name)
# Migrate volumes between hosts
dvbackup backup ./backups volume_name
# Transfer backup file to new host
dvbackup restore ./backups volume_name
```
### Common Volume Patterns
```bash
# Database volumes
docker volume create postgres_data
docker run -v postgres_data:/var/lib/postgresql/data postgres
# Application data
docker volume create app_data
docker run -v app_data:/app/data my_app
# Configuration volumes
docker volume create app_config
docker run -v app_config:/app/config my_app
# Cache volumes
docker volume create app_cache
docker run -v app_cache:/app/cache my_app
```
---
## Testing Types
**Date:** 2025-03-11
**URL:** https://lorbic.com/testing-types/
**Description:** Understanding different types of software testing is crucial for delivering a reliable application. Smoke Testing checks basic stability after a new build, while Sanity Testing verifies specific bug fixes or minor updates. Functional Testing ensures that features work as expected based on business requirements. Regression Testing prevents new changes from breaking existing functionality. End-to-End (E2E) Testing simulates real-world user workflows, and Performance Testing checks system speed, load handling capacity, and responsiveness. Implementing these (some or all) test types helps maintain software quality and prevent critical failures.
Understanding different types of software testing is crucial for delivering a reliable application. Smoke Testing checks basic stability after a new build, while Sanity Testing verifies specific bug fixes or minor updates. Functional Testing ensures that features work as expected based on business requirements. Regression Testing prevents new changes from breaking existing functionality. End-to-End (E2E) Testing simulates real-world user workflows, and Performance Testing checks system speed, load handling capacity, and responsiveness. Implementing these (some or all) test types helps maintain software quality and prevent critical failures.
Here's a basic explanation of each test type with simple examples:
## 1. Smoke Testing
Purpose: Ensures that the core functionality of the application is working before deeper testing. It acts as a basic stability check after a build or deployment.
Example:
• Checking if the application launches successfully.
• Verifying if a user can log in with valid credentials.
• Ensuring the homepage loads without errors.
💡 Analogy: Like checking if a car starts before going on a long drive.
## 2. Sanity Testing
Purpose: A quick check of specific functionality after minor changes or bug fixes to ensure they work as expected. It is narrower than smoke testing.
Example:
• Verifying if a fixed issue (e.g., password reset functionality) works correctly.
• Ensuring a new button added to the UI works as expected.
• Checking if a database update reflects correctly in the UI.
💡 Analogy: Like fixing a broken switch in a house and ensuring only that switch works, without checking all the lights.
## 3. Functional Testing
Purpose: Tests whether the application behaves as expected according to business requirements. It focuses on what the system does.
Example:
• Testing a shopping cart to see if adding/removing items works correctly.
• Checking if an email is sent when a user registers.
• Ensuring a user can apply a discount coupon and see the correct price.
💡 Analogy: Like testing if a vending machine dispenses the correct snack when the right button is pressed.
## 4. Regression Testing
Purpose: Ensures that recent code changes do not break existing functionality. It is done after bug fixes, updates, or new feature additions.
Example:
• After updating the login process, testing if previous login methods (Google, Facebook) still work.
• Ensuring a new feature in a banking app does not break existing transactions.
• After fixing a checkout bug, verifying if other payment options still work.
💡 Analogy: Like fixing a broken pipe in a house and checking if all other plumbing still works.
## 5. End-to-End (E2E) Testing
Purpose: Tests the entire user journey across multiple integrated systems, mimicking real-world usage.
Example:
• Verifying if a user can register, search for a product, add it to the cart, make a payment, and receive an order confirmation email.
• Testing if a banking app allows fund transfers, sends notifications, and updates transaction history correctly.
Testing.
💡 Analogy: Like checking if a restaurant experience flows smoothly: from ordering food to payment and receiving a bill.
## 6. Performance Testing
Purpose: Checks how the system performs under different loads, ensuring speed, scalability, and responsiveness.
Example:
• Measuring if a website loads within 2 seconds under normal traffic.
• Checking if a mobile app can handle 10,000 users at the same time.
• Verifying if a database query retrieves results within an acceptable time limit.
💡 Analogy: Like stress-testing a bridge to see how much weight it can handle before it collapses.
---
## Tools I Use on My Mac
**Date:** 2025-03-10
**URL:** https://lorbic.com/tools-i-use-on-my-mac/
**Description:**
# Tools I Use on My Mac
As a new Mac user, it has been a tough journey getting used to limitations of macOS compare to linux based os. I rely on a set of carefully chosen tools to improve productivity, streamline workflows, and make my overall experience less frustrating. Here's a look at top 20 essential apps I use daily:
## System & UI Enhancements
### 1. Scroll Reverser
Allows me to reverse the scrolling direction for trackpads and mice independently, making navigation more intuitive.
### 2. BeardedSpice
A must-have for controlling media playback on websites and apps using my keyboard's media keys. It can control Spotify.
### 3. KDE Connect
Seamlessly integrates my Mac with my Android phone, enabling file transfers, notifications, and remote input control.
### 4. Flux
Automatically adjusts my screen's color temperature based on the time of day, reducing eye strain and improving sleep.
### 5. Shottr
A lightweight and fast screenshot tool that includes built-in annotation and OCR capabilities.
### 6. Maccy
A clipboard manager that keeps track of copied text and allows quick retrieval of previous copies.
### 7. GPG Keychain
Essential for managing GPG encryption keys for secure email communication and file encryption.
### 8. Music Decoy
Helps me keep block apple music from launching whenever I connect my earphones/headphones. What a stupid idea to auto launch it.
### 9. AltTab
Brings a Windows-style Alt+Tab app switcher to macOS, making app switching faster and more convenient.
### 10. Rectangle
A powerful window management tool that lets me quickly arrange and snap windows using keyboard shortcuts.
### 11. Monitor Control
Gives me precise control over external monitor brightness and volume directly from macOS.
## Development & Productivity
### 12. Docker
Enables me to run containerized applications, making development and deployment more efficient.
### 13. iTerm2
A feature-packed terminal replacement that enhances productivity with split panes, custom profiles, and better performance.
### 14. Obsidian
My go-to knowledge management tool for organizing notes, ideas, and projects in a Markdown-based system.
### 15. Postman
A great API testing tool that helps me debug and develop RESTful services with ease.
### 16. JetBrains Fleet/GoLand/PyCharm
A suit of powerful and modern IDEs from JetBrains that provide world's best coding experience.
### 17. VS Code
Well, we all know what it is. Anyways, it's a highly customizable and extensible code editor that I use for various programming tasks.
### 18. Sublime Merge
A fast and powerful Git GUI that makes managing repositories much smoother.
### 19. Scrcpy
A fantastic open-source tool for mirroring and controlling my Android phone from my Mac.
### 20. ChatGPT
I use ChatGPT for brainstorming, coding assistance, and getting quick explanations on technical topics.
These tools have significantly improved my daily workflow, making my Mac experience more efficient and enjoyable. If you use any of these or have other recommendations, do let me know!
---
## Understanding T and *T method receivers in Go
**Date:** 2025-02-23
**URL:** https://lorbic.com/method-receivers-in-go/
**Description:** In Go, method receivers determine whether a method acts on a copy of a value or a reference to it. This choice isn't just about performance; it affects correctness and behavior, especially when dealing with synchronization primitives (mutex, wait group, etc), slices, and embedded types.
In Go, method receivers determine whether a method acts on a copy of a value or a reference to it. This choice isn't just about performance; it affects correctness and behavior, especially when dealing with synchronization primitives (mutex, wait group, etc), slices, and embedded types.
In this post I explore when to use T (a value receiver) vs. \*T (a pointer receiver) and why, in most cases, pointer receivers should be the default and preferred.
---
#### Understanding T and \*T
In Go, every type T has an associated pointer type \*T. Taking the address of a T variable results in a \*T:
```go
type T struct {
a int
b bool
}
var t T // t is of type T
var p = &t // p is of type *T
```
T and \*T are distinct types. You can't substitute \*T where T is expected and vice versa.
#### Declaring Methods on Types
Go allows you to declare methods on any type you define in your package. That means you can attach methods to both T and \*T:
```go
func (t T) ValueMethod() { /* operates on a copy */ }
func (t *T) PointerMethod() { /* operates on the original */ }
```
Now the billion dollar question: When should a method use a pointer receiver?
#### When to Use a Pointer Receiver
##### 1. The method modifies the receiver.
If your method changes the state of T, you must use \*T, or modifications won't persist.
```go
func (p *Person) Rename(name string) {
p.Name = name
}
```
##### 2. The type is large.
Passing large structs by value incurs unnecessary copying.
```go
type BigStruct struct {
Data [1024]byte
}
func (b BigStruct) BadMethod() { /* Copies 1024 bytes */ }
func (b *BigStruct) GoodMethod() { /* Uses reference of the 1024 bytes */ }
```
##### 3. The type contains synchronization primitives (e.g., sync.Mutex).
Copying a sync.Mutex defeats it purpose of maintaining the state.
```go
type Counter struct {
mu sync.Mutex
val int
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.val++
}
```
Declaring Increment on Counter (not \*Counter) would copy mu, making it useless.
##### 4. The type is meant to be used via pointers.
Some types naturally work as pointers, such as linked list nodes.
##### 5. The type is embedded in another struct.
If a type is meant to be embedded, methods must use pointer receivers to avoid unintended copies. Copies introduce performance penalty.
```go
type Stats struct {
a, b, c Counter
}
func (s Stats) Sum() int {
return s.a.Increment() + s.b.Increment() + s.c.Increment() // Copies `Counter`, breaks mutex
}
```
#### When To Use a Value Receiver?
A value receiver is fine if:
- The method does not modify the receiver.
- The type is small and simple (like int, bool, or struct{X, Y int}).
- The type is inherently immutable.
For example:
```go
type Point struct {
X, Y int
}
func (p Point) Distance(q Point) float64 {
dx, dy := float64(q.X-p.X), float64(q.Y-p.Y)
return math.Sqrt(dx*dx + dy*dy)
}
```
Here, Distance doesn't modify Point, and copying two ints is negligible.
#### Should Methods That Don't Mutate Use a Pointer Receiver?
Yes, in most cases. Even if a method doesn't modify the receiver, using \*T avoids unintended copies and maintains consistency across your codebase.
The exceptions:
- Small, immutable types (e.g., Point).
- Types that should be copied intentionally, like function options or temporary configurations.
Basically:
- Default to using \*T (reference receiver) unless you have a good reason not to.
- Use T (value receiver) only when your type is small and meant to be copied.
- Never use T (value receiver) if the type has a sync.Mutex, a slice, or is embedded in another struct.
By following these guidelines, you avoid subtle bugs and unintended performance penalties in your Go code.
Cheers!!
Happy coding.
---
## Analysis Paralysis in Engineering Teams
**Date:** 2025-02-10
**URL:** https://lorbic.com/analysis-paralysis/
**Description:** In engineering, progress is key. However, sometimes teams get stuck in endless discussions, over-planning, and constant changes, delaying actual work. This situation is called "Analysis Paralysis." It happens when people focus too much on making perfect decisions instead of moving forward with practical solutions.
Analysis Paralysis in Engineering

In engineering, progress is key. However, sometimes teams get stuck in endless discussions, over-planning, and constant changes, delaying actual work. This situation is called "Analysis Paralysis." It happens when people focus too much on making perfect decisions instead of moving forward with practical solutions.
One common cause of analysis paralysis is fear of failure. Engineers and managers want to avoid mistakes, so they keep analyzing every possible outcome. While planning is important, overthinking can waste time and resources. Another reason is complex decision-making. If too many people are involved, or if there are too many options, teams struggle to decide and keep delaying action.
For example, imagine a software development team working on a new app. They spend weeks debating the best database technology: SQL or NoSQL. They read articles, compare benchmarks, and discuss performance differences. Meanwhile, no actual coding happens. Instead of choosing one and adjusting later if needed, they waste valuable time in discussions.
The solution to analysis paralysis is to set clear deadlines for decisions and follow the "good enough" principle. Instead of chasing perfection, engineers should pick a reasonable option and refine it along the way. Agile development, for instance, focuses on building a minimum viable product (MVP) and improving it step by step rather than perfecting everything upfront.
In short, analysis paralysis slows down innovation. While careful planning is necessary, taking action is just as important. Engineers must find the right balance: analyzing enough to make informed decisions but not so much that progress stops.
---
## Go Clean Code Guidelines
**Date:** 2024-09-22
**URL:** https://lorbic.com/go-clean-code-guidelines/
**Description:** When it comes to writing clean, maintainable code, there are a few fundamental rules that can help improve the overall structure and quality of your codebase. As engineers, our goal should be to keep things simple, clear, and scalable. With this in mind, here are some guidelines which prioritize code readability, functional clarity, and the overall maintainability of a project. These guidelines are based on principles from clean code, SOLID, and functional programming while emphasizing simplicity over unnecessary complexity.
### Go Clean Code Guidelines for Code Quality and Maintainability.
When it comes to writing clean, maintainable code, there are a few fundamental rules that can help improve the overall structure and quality of your codebase. As engineers, our goal should be to keep things simple, clear, and scalable. With this in mind, here are some guidelines which prioritize code readability, functional clarity, and the overall maintainability of a project.
These guidelines are based on principles from clean code, SOLID, and functional programming while emphasizing simplicity over unnecessary complexity.
---
### Rule 1: Function Naming Clarity
Your function names must clearly indicate what they do. Avoid vague names or overly complex abstractions. Each function should serve a single purpose, and its name should reflect this responsibility.
#### Example:
Instead of a vague name like `ProcessData`:
```go
// Bad
func ProcessData() {
// Complex logic for processing some data
}
```
Use something more descriptive like `ConvertOrderToInvoice`:
```go
// Good
func ConvertOrderToInvoice(order Order) Invoice {
// Convert an Order object into an Invoice
}
```
Here, the function name precisely conveys what the function does, making it easier for developers to follow the code.
### Rule 2: No Magic Numbers or Strings
Avoid using magic numbers or strings directly in your code. Instead, define constants with meaningful names to improve readability and reduce errors.
#### Example:
```go
// Bad
if user.Role == "admin" {
// Grant access
}
```
Replace magic strings with constants:
```go
// Good
const AdminRole = "admin"
if user.Role == AdminRole {
// Grant access
}
```
This makes the code more readable and easier to maintain. If the role name changes in the future, you only need to update it in one place.
### Rule 3: Use Clear and Consistent Variable Names
Variable names should be descriptive enough to indicate their purpose. Do not abbreviate in a way that makes it hard for others to understand the meaning of the variable.
#### Example:
```go
// Bad
v := 10 // What is 'v'?
```
Instead, use meaningful names:
```go
// Good
maxAllowedItems := 10
```
With clear variable names, other developers can quickly understand what the variable represents.
### Rule 4: Keep Functions Small
Each function should perform one task and do it well. If a function is doing multiple things, break it down into smaller functions. This improves code readability and makes testing easier.
#### Example:
```go
// Bad
func HandleOrder(order Order) Invoice {
// Generating invoice, many lines of code
// Save invoice to database, many lines of code
// Send notification to customer, many lines of code
return invoice
}
```
The function is doing too many things. Instead, split it into smaller functions:
```go
// Good
func HandleOrder(order Order) Invoice {
invoice := generateInvoice(order)
persistInvoice(invoice)
notifyCustomer(invoice)
return invoice
}
func persistInvoice(invoice Invoice) {
// Save invoice to the database
}
func notifyCustomer(invoice Invoice) {
// Send a notification to the customer
}
```
This makes each function's responsibility clearer, and it is easier to test and maintain.
### Rule 5: Error Handling Should Be Explicit
Always check for errors and handle them explicitly. Do not assume the absence of an error. The code should either handle the error gracefully or propagate it back to the caller.
#### Example:
```go
// Bad
result, err := getUserDetails(userID)
process(result) // No error handling!
```
Instead, always handle or propagate errors:
```go
// Good
result, err := getUserDetails(userID)
if err != nil {
logError(err)
return nil, err
}
process(result)
```
Proper error handling ensures that bugs and edge cases are caught early and makes the code more reliable.
### Rule 6: Use Structs for Complex Data
If a function accepts multiple parameters of related data, bundle them into a struct. This makes the function signature cleaner and more flexible.
#### Example:
```go
// Bad
func CreateUser(name string, age int, address string, email string) User {
// Create a new user
}
```
Instead, use a struct for the user's details:
```go
// Good
type UserDetails struct {
Name string
Age int
Address string
Email string
}
func CreateUser(details UserDetails) User {
// Create a new user
}
```
This approach makes the code easier to read and modify in the future, especially if more fields are added to the user details.
### Rule 7: Use Consistent Struct Field Order
Maintain consistency in the order of struct fields. Group similar fields together to enhance readability.
#### Example:
```go
// Bad
type User struct {
Address string
Age int
Email string
Name string
}
```
Instead, group fields logically:
```go
// Good
type User struct {
Name string
Age int
Address string
Email string
}
```
This way, when you or others revisit the code, it's easier to understand the structure of the object.
### Rule 8: Inline Commenting for Complex Logic
Where necessary, provide inline comments explaining the purpose of complex logic or algorithms. Avoid obvious comments, but make sure to clarify non-obvious code.
#### Example:
```go
// Bad
// Add two numbers
total := a + b
```
Instead, explain complex logic:
```go
// Good
// Apply discount if the customer is a premium user and their purchase exceeds $100
if customer.IsPremium && order.Total > 100 {
applyDiscount(order)
}
```
The inline comment explains the logic behind applying the discount, which may not be immediately apparent from the code itself.
### Rule 9: Group Related Code into Logical Blocks
Separate blocks of code that serve different purposes with blank lines. This improves readability and helps group related logic together.
#### Example:
```go
// Bad
func ProcessOrder(order Order) {
validateOrder(order)
applyDiscount(order)
finalizePayment(order)
sendReceipt(order)
}
```
Instead, separate the code into logical sections:
```go
// Good
func ProcessOrder(order Order) {
validateOrder(order)
applyDiscount(order)
finalizePayment(order)
sendReceipt(order)
}
```
This makes the code visually easier to follow and highlights the different stages of processing an order.
### Rule 10: Function Arguments vs. Return Types
Make sure function names clearly reflect their return types and arguments. This prevents confusion and makes the function's purpose obvious to the caller.
#### Example:
```go
// Bad
func FetchData(input string) bool {
// Returning a boolean from a 'Fetch' function is misleading
}
```
Instead, update the name to reflect the return type:
```go
// Good
func IsDataAvailable(input string) bool {
// Now it's clear that the function returns a boolean
}
```
#### This helps maintain consistency in your codebase and makes the function's role immediately clear.
By following these guidelines, you can ensure that your codebase remains clean, efficient, and easier to navigate for you and your team. Keep function names clear, avoid magic numbers, handle errors explicitly, and group your code logically for the best results.
Happy coding!
---
## SOLID and Functional Programming Principles in Go
**Date:** 2024-09-22
**URL:** https://lorbic.com/solid-and-functional-programming-principles-in-go/
**Description:** SOLID and functional programming principles explained and implemented in Go
Let's go through the **SOLID principles** and **functional programming principles** that can apply to your Go codebase. I'll provide simple Go examples along with brief explanations to show how each principle can improve code quality.
---
### **SOLID Principles**
1. **S**ingle Responsibility Principle (SRP)
- **Description:** A class or function should have only one reason to change, meaning it should only have one job or responsibility.
**Example:**
```go
// Good: Separate responsibilities into two functions
type EmailSender struct{}
func (e *EmailSender) SendEmail(to, subject, body string) {
// logic for sending email
}
func formatEmailBody(template string, data map[string]string) string {
// logic for formatting the email body
return ""
}
// Avoid: Single function doing multiple jobs
func sendFormattedEmail(to, subject, template string, data map[string]string) {
body := formatEmailBody(template, data)
// email sending logic mixed with formatting
}
```
---
2. **O**pen/Closed Principle (OCP)
- **Description:** Software entities (classes, modules, functions) should be open for extension but closed for modification.
**Example:**
```go
// Good: Extend functionality via interfaces
type PaymentProcessor interface {
ProcessPayment(amount float64) error
}
type PayPalProcessor struct{}
func (p PayPalProcessor) ProcessPayment(amount float64) error {
// PayPal payment processing logic
return nil
}
type CreditCardProcessor struct{}
func (c CreditCardProcessor) ProcessPayment(amount float64) error {
// Credit card processing logic
return nil
}
// Avoid: Modifying existing functions to add new payment methods
func processPayment(method string, amount float64) error {
if method == "paypal" {
// PayPal logic
} else if method == "creditcard" {
// Credit card logic
}
return nil
}
```
---
3. **L**iskov Substitution Principle (LSP)
- **Description:** Objects should be replaceable by their subtypes without altering the correctness of the program.
**Example:**
```go
// Good: Subtypes maintain expected behavior
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string {
return "Woof!"
}
type Cat struct{}
func (c Cat) Speak() string {
return "Meow!"
}
func makeAnimalSpeak(a Animal) {
fmt.Println(a.Speak())
}
// Avoid: Subtypes behaving unpredictably
type SilentDog struct{}
func (s SilentDog) Speak() string {
return "" // Violates expectations of the Speak method
}
```
---
4. **I**nterface Segregation Principle (ISP)
- **Description:** No client should be forced to depend on methods it doesn't use. Create small, specific interfaces instead of one large interface.
**Example:**
```go
// Good: Segregated interfaces
type Reader interface {
Read() string
}
type Writer interface {
Write(data string) error
}
// Avoid: Fat interface forcing implementations to use unused methods
type ReadWriteCloser interface {
Read() string
Write(data string) error
Close() error
}
// If a class only needs reading, it should not be forced to implement Write and Close.
```
---
5. **D**ependency Inversion Principle (DIP)
- **Description:** High-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces).
**Example:**
```go
// Good: High-level module depends on abstraction
type NotificationService struct {
sender EmailSender
}
func NewNotificationService(sender EmailSender) *NotificationService {
return &NotificationService{sender: sender}
}
func (n *NotificationService) Notify(message string) {
n.sender.SendEmail("user@example.com", "Notification", message)
}
// Avoid: High-level module directly depending on a low-level module
func sendNotification() {
sender := &EmailSender{} // tight coupling with EmailSender
sender.SendEmail("user@example.com", "Notification", "Hello!")
}
```
---
### **Functional Programming Principles**
1. **First-Class and Higher-Order Functions**
- **Description:** Functions are treated as first-class citizens and can be passed around as arguments, returned from other functions, or assigned to variables.
**Example:**
```go
// Higher-order function that accepts another function as a parameter
func applyDiscount(price float64, discountFunc func(float64) float64) float64 {
return discountFunc(price)
}
func tenPercentDiscount(price float64) float64 {
return price * 0.9
}
func main() {
price := 100.0
discountedPrice := applyDiscount(price, tenPercentDiscount)
fmt.Println(discountedPrice) // 90.0
}
```
---
2. **Pure Functions**
- **Description:** A pure function's output is determined only by its input values, without observable side effects.
**Example:**
```go
// Good: Pure function (no side effects)
func add(a, b int) int {
return a + b
}
// Avoid: Impure function (with side effects)
var counter int
func addWithSideEffect(a, b int) int {
counter++ // changes external state
return a + b
}
```
---
3. **Immutability**
- **Description:** Data should not be modified after it is created. Instead, create a new copy of the data when changes are needed.
**Example:**
```go
// Good: Immutability by creating a new slice
func addToSlice(slice []int, value int) []int {
newSlice := append(slice, value)
return newSlice
}
// Avoid: Modifying the original slice
func modifySlice(slice []int, value int) {
slice = append(slice, value)
}
```
---
4. **Recursion Over Loops**
- **Description:** Functional programming often favors recursion over iterative loops, especially when solving problems like list processing.
**Example:**
```go
// Good: Recursion
func factorial(n int) int {
if n == 0 {
return 1
}
return n * factorial(n-1)
}
// Avoid: Iterative approach (loops)
func iterativeFactorial(n int) int {
result := 1
for i := n; i > 0; i-- {
result *= i
}
return result
}
```
---
5. **Function Composition**
- **Description:** Combine simple functions to build more complex ones, allowing for clean and reusable logic.
**Example:**
```go
func double(x int) int {
return x * 2
}
func square(x int) int {
return x * x
}
func compose(f, g func(int) int) func(int) int {
return func(x int) int {
return f(g(x)) // Apply g, then f
}
}
func main() {
doubleSquare := compose(double, square)
fmt.Println(doubleSquare(3)) // Output: 18 (3^2 * 2)
}
```
---
These principles can help keep your code clean, modular, and testable while using both object-oriented and functional paradigms.
---
## 10 Essential Tips for Beginners Starting in IT
**Date:** 2024-02-23
**URL:** https://lorbic.com/essential-tips-for-beginners-starting-in-it/
**Description:** In the ever-evolving world of IT, prioritize mastering core concepts over chasing trends. Embrace hands-on learning through projects, stay curious, seek guidance when needed, and remember that problem-solving and persistence are key to success in this dynamic field.

Are you new to IT? Feeling a bit overwhelmed? Don't worry, I've got you covered! In this article, I'll share 10 essential tips to help you get started on your journey in Information Technology. From mastering the basics to gaining hands-on experience and staying curious, these tips will set you on the right path. Let's dive in and start the IT adventure!
1. **Focus on Fundamentals:** Instead of trying to understand every buzzword out there or the latest tech trend, focus on building a strong foundation in core concepts such as networking, operating systems, databases, and programming languages.
2. **Hands-on Practice:** Don't just rely on theory. Get your hands dirty by working on projects, setting up environments, and troubleshooting issues. Practical experience is invaluable in IT. I can tell you from personal experience, it doesn't matter what you know or which course you have completed, only thing that matters is if you can convert that Jira ticket into some sweet .py files 😉.
3. **Learn by Doing:** Regularly work on projects and real-world scenarios. Whether it's setting up a home lab, create open-source projects (Invite your internet friends to add features). Practical experience is the most effective way to understand complex stuff, eg. like how that payment is processed in the eCommerce website and how you can do it on your own. Create imaginary scenarios like there is some XYZ that sells car parts and you are responsible for all tech things, now how will you design, build, host a website where you will sell those parts. Some projects can be simple 1 hour coding, some will take many months to complete, once you are addicted you can't go back. **YOU NEED THAT ADDICTION** in this distracted, shorts-oriented world.
4. **Stay Curious:** The field of IT is rapidly changing (new JS and CSS frameworks being born every week), so it's essential to stay curious and keep learning. Be open to exploring new technologies, tools, and methodologies to expand your knowledge and skills continuously. Like the AI things going on right now. But don't distract from your path.
5. **Need Help? ask for it:** Don't hesitate to reach out to more experienced professionals for guidance or mentorship. Not everyone you ask will help you, but if you ask 10 people at least 1 may help you. As we say in Hindi *"*जहाँ अहंकार होता है, वहाँ ज्ञान नहीं होता", which translates to "Where there is pride, there is no wisdom" in English.
6. **Stay Updated but Don't Chase Every Trend:** Stay informed about industry trends and advancements, but don't feel pressured to chase every new technology or buzzword. Instead, focus on understanding the underlying principles and how they apply to your work. You can't master everything. Focus on the things you care and are useful.
7. **Practice Problem-Solving:** Our industry always revolves around solving complex problems and troubleshooting issues. Strengthen your problem-solving skills by tackling challenges, breaking down problems into smaller steps, and systematically finding solutions. I'm not talking about mindlessly doing DSA questions. There are other problems that need solutions. Such as, how will you modernize and deploy a decade old monolith into cloud which is so goddamn fragile, you touch it, it breaks!
8. **Document and read docs:** Keep track of your learning journey by documenting your progress, experiences, and lessons learned. Reflecting on your achievements and challenges can help remember your understanding and identify areas for improvement. For this build your own blog.
9. **Stay Patient and Persistent:** Learning IT is challenging, and you will encounter setbacks along the way. Stay patient, be persistent, and don't get discouraged by obstacles. Every challenge is an opportunity to learn and grow. Back in college, when I was learning Django and working on my first project there was an issue with my implementation which took over a week to find it and fix it.
10. **Enjoy the Journey:** Remember to enjoy the learning process and celebrate your successes, no matter how small. IT is a fascinating and rewarding field, and embracing the journey of continuous learning can lead to fulfilling and meaningful career opportunities.
Thinking something? Write it down in the comments.
Have fun. Happy learning.
---
## NGINX: Building from Source and Installation on Linux (Updated)
**Date:** 2024-02-02
**URL:** https://lorbic.com/build-nginx-from-source/
**Description:** In this blog we are going to build NGINX from source code. And we will configure NGINX's settings, paths, and add or remove modules.
[NGINX](https://en.wikipedia.org/wiki/Nginx) is a web server that can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache. NGINX is a free and open source software licensed under _2-clause BSD_.\
You can easily download and use NGINX in Windows, macOS, Linux and other operating systems [link](https://nginx.org/en/download.html) read NGINX installation instructions from the [official docs](https://nginx.org/en/docs/install.html) and install on your operating system for free.
But, in this blog we are going to build NGINX from source code. And we will configure NGINX's settings, paths, and add or remove modules.
So let's get started…
## Preparation
We'll use Ubuntu 20.04 LTS as our operating system, though these instructions are applicable to other Linux-based systems as well.
### 1. Download the source code:
Start by visiting the NGINX download page and choose either the stable release or the mainline version for experimental features. For example, you can download nginx-1.21.4.
Link: [NGINX download page](https://nginx.org/en/download.html). \
Note: You can use `wget` or `curl` to download.
```shell
wget https://nginx.org/download/nginx-1.21.4.tar.gz
```
After downloading, extract the tar file using:
```shell
tar -zxvf nginx-1.21.4.tar.gz
```
Now cd into `nginx-` directory.
### 2. Install Required Tools:
Ensure you have the necessary build tools. On Ubuntu, use `apt` package manager:
```shell
sudo apt install build-essential
```
Additionally, install required dependencies and libraries:
```shell
sudo apt install libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev
```
### 3. Configure NGINX for build
Check all configuration options:
`sudo ./configure --help`
Refer to the NGINX documentation's module reference section for details on modules. Configure installation paths and modules as needed.\
Follow the link: [nginx docs > module reference section](https://nginx.org/en/docs/)
Configure Installation:
```shell
sudo ./configure \
--sbin-path=/usr/bin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--with-pcre \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_gunzip_module
```
> –sbin-path=/usr/bin/nginx\
> –conf-path=/etc/nginx/nginx.conf\
> –error-log-path=/var/log/nginx/error.log\
> –http-log-path=/var/log/nginx/access.log\
> –pid-path=/var/run/nginx.pid\
> –with-pcre --with-http_ssl_module\
> –with-http_v2_module\
> –with-http_gunzip_module
### 4. Compile and Install the Application:
Compile NGINX by running:
```shell
make
# Run below command to install NGINX
make install
```
### 5. Restart NGINX and Configure as a Service:
Reload NGINX to apply changes:
`nginx -s reload`
**If you encounter an error related to the nginx.pid file missing, follow these steps:**
> nginx: \[error] open() "/var/run/nginx.pid" failed (2: No such file or directory)
**5.1. Add Nginx as service**:
Add NGINX as a service by creating a systemd config file. Create or modify `/lib/systemd/system/nginx.service` with appropriate paths:\
Visit: [nginx systemd config](https://www.nginx.com/resources/wiki/start/topics/examples/systemd/) and create the file.\
_`--/lib/systemd/system/nginx.service--`_\
Change _pid_ and _sbin_ path as set in step 3.
```/lib/systemd/system/nginx.service
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/bin/nginx -t
ExecStart=/usr/bin/nginx
ExecReload=/usr/bin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
```
**5.2. Start NGINX using systemd:**
```sh
sudo systemctl start nginx
```
**5.3. Enable NGINX to start on boot:**
```sh
sudo systemctl enable nginx
```
That's all you need to do to compile and run NGINX on Ubuntu.\
If you get any error or suggestion please leave a comment.
Happy NGINX-ing! 🤟
---
## How to Install Docker on Another Drive in Windows (D: Drive Guide)
**Date:** 2024-01-27
**URL:** https://lorbic.com/docker-custom-installation-location-windows/
**Description:** Is your C: drive full? Learn how to install Docker Desktop in a custom location (like a D: drive) on Windows 10 or 11 using CLI flags for WSL2 data and container roots.
While installing Docker on Windows typically forces it onto your **C: drive**, many developers run out of space as images and containers grow. This guide shows you how to bypass the GUI and use CLI flags to install Docker Desktop in a custom location (e.g., `D:\Docker`) while also moving the heavy WSL2 data roots.
**TL;DR:** To save your `C:` drive from Docker's growing appetite, bypass the GUI installer. Open PowerShell as Admin and run:
`start /w "" "Docker Desktop Installer.exe" install --accept-license --installation-dir="D:\Docker" --wsl-default-data-root="D:\Docker\wsl"`
---
### Requirements for Custom Installation
To ensure a smooth migration to another drive, verify you meet these criteria:
- **OS:** Windows 10 or 11 (with Hyper-V and WSL 2 enabled).
- **Installer:** The latest Docker Desktop `.exe` [downloaded here](https://docs.docker.com/desktop/install/windows-install/).
- **Permissions:** Administrator access.
- **Storage:** A secondary drive (D:, E:, etc.) with at least 64GB of free space (SSD recommended for performance).
### Preparation
1. **Create Folders:** Create your target directory. For example: `D:\Containers`.
2. **Cleanup:** If you have an existing Docker installation, back up your volumes and uninstall it first.
3. **Stop Services:** Open PowerShell as admin and run `sc.exe stop docker` to ensure no locks are active.
### Recommended Directory Structure
For a clean setup, use a structure like this on your secondary drive:
```text
D:\CONTAINERS
├───docker (App files)
└───wsl (Linux container data)
└───windows-data (Windows Container Data)
```
### Step-by-Step Installation via CLI
The GUI installer doesn't offer a "Browse" button for the path. You must run it from the command line (PowerShell or CMD) with specific flags.
**The Complete Command:**
```powershell
start /w "" "Docker Desktop Installer.exe" install --accept-license \
--installation-dir="D:\Containers\docker" \
--wsl-default-data-root="D:\Containers\wsl" \
--windows-containers-default-data-root="D:\Containers\windows-data"
```
#### Flag Explanations:
- `--installation-dir`: Moves the actual Docker application binaries (usually `C:\Program Files\Docker\Docker`).
- `--wsl-default-data-root`: **The most important flag.** This moves the massive `ext4.vhdx` files where your Linux containers actually live.
- `--windows-containers-default-data-root`: Moves the data root for Windows-native containers.
_Note: Replace `D:\Containers` with your actual drive letter._
### Post-Installation & Verification
1. **Restart your computer** to ensure all registry changes and WSL paths are initialized.
2. **Verify paths:** Open PowerShell and run:
```powershell
docker info | select-string "Docker Root Dir"
```
3. **Check WSL:** Verify the data is being stored in your new location by checking the folder size of your `wsl` directory after pulling a few large images.
### Why move Docker to another drive?
- **Performance:** Offloading I/O to a dedicated SSD can prevent OS lag during heavy builds.
- **Stability:** Prevents "Disk Full" errors that can crash Windows when Docker pulls large image layers.
- **Organization:** Keeps your system drive lean and focused strictly on the OS.
---
**Stop fighting your tools.** If you found this useful, join the **Dispatch**—a weekly deep dive into the mechanics of high-performance systems, Go internals, and devops architecture.
{{< newsletter >}}
---
## Build a URL redirector application with Cloudflare Workers and Cloudflare D1
**Date:** 2024-01-07
**URL:** https://lorbic.com/build-a-url-redirector-application-with-cloudflare-workers-and-cloudflare-d1/
**Description:** Discover the power of Cloudflare Workers and D1 database as we guide you through building a robust URL redirector application on LorbiC.com. Shorten and customize your links effortlessly, optimizing user experience and website performance. Learn step-by-step with prerequisites, database setup, and code implementation. Unlock the potential of Cloudflare's edge computing and revolutionize URL handling for seamless redirections. Elevate your web application's performance with this comprehensive guide at Lorbic.com.

In today's fast-paced digital world, where attention spans are short, optimizing website performance and user experience is crucial. Imagine asking someone to visit a lengthy URL () – their reaction might be a disappointed face (🙁). Typing such URLs can lead to errors, resulting in users landing on a dreaded 404 page.
To address this, we'll build a simple and powerful solution – a URL redirector application using Cloudflare Workers and D1 database. This application will not only shorten your links but also provide a seamless and error-free redirection feature.\
\
For the sake of simplicity, we'll keep the set of features to a minimum and add whatever necessary at some later time.
### Main features:
* Create a short code for a URL.
* Redirect users to the original link.
### Understanding Cloudflare Workers:
Cloudflare Workers allow developers to run code at the edge of the Cloudflare network, enabling the execution of custom logic for HTTP requests. This allows for enhanced performance and reduced latency, as the code runs closer to the end-users.
That's what Workers are, basically intercepting requests before they reach your origin server. This allows for lightning-fast redirects based on URL paths, query parameters, headers, and even cookies. You can put workers between **USER** and **ORIGIN SERVER.** Then handle the request accordingly.
#### **Here's how Workers handle redirects:**
* **Interception:** The Worker intercepts incoming requests based on your chosen route configuration.
* **Rule Matching:** The Worker analyzes the request against your predefined rules, stored in JavaScript code, or you can connect Cloudflare KV, Cloudflare D1 or other database via Cloudflare Hyperdrive and get the configuration.
* **Redirection Magic:** If a rule matches, the Worker constructs a redirect response, specifying the new target URL and status code (e.g., 301 for permanent move, 302 for temporary).
* **Speedy Delivery:** The redirect response is instantly delivered back to the user, bypassing the origin server for optimal performance.
- - -
### Prerequisites:
Before diving into the implementation, ensure you have the following:
* Node JS
* A Cloudflare account.
* A domain configured with Cloudflare.
* Cloudflare Wrangler CLI (check [here](https://developers.cloudflare.com/workers/wrangler/install-and-update/))
* Familiarity with JavaScript, Node.js, and ExpressJS (we'll use HonoJS, similar to ExpressJS).
* Install Hono js.
### Create Cloudflare D1 Database
Login to Cloudflare Wrangler CLI by running the following command and allow Cloudflare permissions.
```javascript
wrangler login
```
##### Create a D1 database
Run the command below to create a database. Change with your actual database name.
```shell
wrangler d1 create
```
This returns following response, with details of your database. \
Paste these into your `wrangler.toml`
```toml
[[d1_databases]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = ""
database_id = "5283redacted23-4a04-456b-af3f-redacted"
```
##### Create database schema
We will keep it very simple with just 1 table and 3 columns in the table. Here is the command to create the database table. **Note:** you'll have to paste the database configuration in **wrangler.toml** and have to be inside the project directory.
```shell
wrangler d1 execute DB \
--command "CREATE TABLE IF NOT EXISTS urls (short_code TEXT PRIMARY KEY, created_at INTEGER, url TEXT);"
```
**Columns:**
* short_code: A string column to store the short code associated with the URL.
* url: A string column to store the full URL.
* created_at: An integer column to store the Unix timestamp representing when the URL was created.
Check your database by running the following command:
```shell
wrangler d1 execute DB \
--command "select * from urls"
```
### Create Cloudflare Worker
Go to [this page](https://developers.cloudflare.com/workers/get-started/guide/) and create the Cloudflare worker. Or simple install Wrangler CLI and run following command to initialize a project.
Change **``** with actual name. (I've chosen **lrbc).**
```shell
npx wrangler init
```
Select, "hello world" example in the list and chose other options accordingly.
Now go to the **lrbc** directory (your project directory).
```shell
cd lrbc
```
Now open the `wrangler.toml` file in the root of your directory. Add the following code to connect your Cloudflare D1 database. If you do not have it set-up check the **Create Cloudflare D1 Database** of this blog.
Replace the name of your database and database id with actual values. The binding is how you will refer to this configuration in your worker code.
```toml
[[d1_databases]]
binding = "DB"
database_name = ""
database_id = ""
```
##### Install Honojs:
Install hono js by running following code `npm install --save hono`.
### The Code:
Next, open the `src/index.js` file and add the following code. It uses Hono JS. Hono is a tiny and super fast framework for creating web application and it is very easy to integrate with Cloudflare Workers. It's feels native.
```javascript
import { Hono } from 'hono';
const app = new Hono();
app.get('/:code', async (c) => {
try {
const code = c.req.param('code');
console.log(code);
const { results } = await c.env.DB.prepare('SELECT url FROM urls WHERE short_code = ?').bind(code).all();
if (results.length > 0) {
const websiteUrl = results[0].url;
console.log('Redirecting to ' + websiteUrl);
return c.redirect(websiteUrl);
} else {
console.log('Short code not found');
return c.json({ status: 404, error: 'Short code not found' });
}
}
catch (e) {
console.log('Error fetching URL:', e);
return c.json({ status: 500, error: 'Failed to fetch URL' });
}
});
export default app;
```
The provided code is written in JavaScript and uses the Hono library. Let's break down its key components:
1. ##### **Route Handling:**
The code defines a route using the 'app.get' method, which responds to incoming HTTP GET requests with a specific parameter in the URL.
```javascript
app.get('/:code', async (c) => {
// Code logic goes here
});
```
2. ##### **Database Query:**
Inside the route handler, the code attempts to fetch the full URL associated with the provided short code from a database. Notice, the **DB** in the code **c.env.DB** . This is the binding we've defined in **wrangler.toml** file. Here **c** is the context of Hono. Everything related request and response is stored in this object.
```javascript
const code = c.req.param('code');
const { results } = await c.env.DB.prepare('SELECT url FROM urls WHERE short_code = ?').bind(code).all();
```
3. ##### URL Redirection or Error Handling:
Based on the query results, the code decides whether to redirect the user to the corresponding website URL or return a JSON response with an error message.
```javascript
if (results.length > 0) {
// Redirect to the full website URL
return c.redirect(websiteUrl);
} else {
// Short code not found, return a JSON response
return c.json({ status: 404, error: 'Short code not found' });
}
```
4. ##### Error Handling:
The code includes basic error handling, logging any encountered errors and returning an appropriate JSON response. You can check these logs in the Workers dashboard. And by running `wrangler tail`
```javascript
} catch (e) {
console.log('Error fetching URL:', e);
return c.json({ status: 500, error: 'Failed to fetch URL' });
}
```
### Deploy your worker:
You can deploy your worker by running just one command `wrangler deploy`. It will create a ***.workers.dev*** URL.
```shell
wrangler deploy
```
### Create Short URLs:
You can either create the URLs by running a following code and directly inserting them into your D1 database.
```javascript
app.post('/store', async (c) => {
try {
// get the long url from json payload in request body
const { url } = await c.req.json();
// Generate a random id of length = NANOID_SIZE
const shortCode = nanoid();
const created_at = Date.now();
console.log(shortCode);
// Validation
if (!shortCode || !url) {
return c.json({status: 400, error: 'Missing short code or URL' });
}
// Save the url and
const { results } = await c.env.DB.prepare("INSERT INTO urls (short_code, url, created_at) VALUES (?, ?, ?)").bind(shortCode, url, created_at).run();
return c.json({ message: `URL stored successfully. short: ${shortCode}, url: ${url}` });
} catch (e) {
console.error('Error storing URL:', e);
return c.json({ status: 500, error: 'Failed to store URL. There is some error or the code already exists.' });
}
});
```
### What's Next
* Create a GitHub repository and store this project there.
* Extend the functionality by adding the short URL creation feature.
* Integrate this worker (project) into your existing website and create a share functionality, so when someone clicks the share button they get a short URL.
* Extend the database schema and add a hash of URL, so creating existing URLs will return the short existing code instead of creating new code, reducing the number of duplicate URLs.
If you have any question, write it down in the comments below. Your response really matters 😅.
Share it with your friends. Have a nice Sunday. Cheers ✌
---
## Setting Up Llama 2 with Docker on Your Gaming Laptop Using Ollama
**Date:** 2023-12-02
**URL:** https://lorbic.com/setting-up-llama-2-with-docker-on-your-gaming-laptop-using-ollama/
**Description:** Effortlessly set up Llama 2 on your gaming laptop using Docker and Ollama, with a user-friendly interface and local data storage for privacy.
This article is simple guide on setting up Llama 2, a powerful large language model, on your gaming laptop using Docker and the Ollama platform. Ollama makes it very easy to run many LLMs locally. In this detailed article, I'll cover each step, such as Ollama installation and ease of interaction through a Chat GPT-like UI. Before we go into the technical details, let's understand what a large language model is.

## What is a Large Language Model?
Large language models, like Llama 2, Code Llama are advanced artificial intelligence algorithms designed to understand and generate human-like language. These models are trained on massive datasets (like thousands of books), learning the fundamentals of language structure, context, and syntax. Llama 2, in particular, is a versatile language model capable of various natural language processing tasks, making it a valuable tool for developers, researchers, and enthusiasts. And it is open source. So, we can use it for free.
## Prerequisites:
Before diving into the installation process, let's ensure your system meets the necessary prerequisites:
* **Minimum RAM:** 16 GB (8 GB is fine but may result in slower performance)
* **Docker:** Install the latest version of Docker on your machine. If you don't have it, visit Docker's official website for detailed installation instructions.
* **For Windows Users:** Install the latest version of Windows Subsystem for Linux (WSL 2). (I couldn't get the GPU to work, I'll learn more and keep this blog updated).
* **For Linux Users:** Ensure you have an Nvidia GPU. Note that you may need the Nvidia Container Toolkit\[3] for GPU support.
## Installing Docker:
If you haven't installed Docker yet, follow these steps:
Download and Install Docker:
1. Visit [Docker's official website](https://www.docker.com/get-started).
2. Choose the right version for your operating system.
3. Follow the installation instructions provided.
## Setting Up Ollama with Docker:
Now, let's set up the Ollama Docker container for Llama 2:
#### 1. Install the Ollama Docker Container:
```shell
docker run -d --gpus=all -v ${PWD}:/root/.ollama -p 11434:11434 --name ollama ollama/ollama
```
* This command downloads the Ollama Docker image and creates a container named "ollama", exposing Ollama's APIs on port 11434.
* For Linux users, the option --gpus=all enables GPU support.
#### 2. Run the Llama 2 Model:
```shell
docker exec -it ollama ollama-run Llama2
```
* Execute this command to run Llama 2 inside the Ollama Docker container.
## Installing Chat GPT-like UI:
Enhance your user experience by installing the Ollama-webui container:
```shell
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway --name ollama-webui --restart always ghcr.io/ollama-webui/ollama-webui:main
```
* This command creates a container named "ollama-webui" and exports it to localhost:3000.
## Accessing Your Chat GPT:
With everything set up, access your **Chat GPT** from your browser at http://localhost:3000. Enjoy the chatting with your AI in a user-friendly interface with all your data stored locally for maximum privacy.

## Additional Tips and Considerations:
Disclaimer: Keep in mind that the response time of Llama 2 may vary depending on your machine's capabilities.
You can also install other models. Find a model from [Ollama Library](https://ollama.ai/library) and run it inside the a container just like we did with Llama 2.
## Reference Links:
* [Stackoverflow - Mount a drive](https://stackoverflow.com/a/41489151/11175853)
* [Docker Official Website](https://docs.docker.com/engine/install/)
* [Ollama Official Website](https://ollama.ai/)
* [](https://ollama.ai/)[Ollama Models Library](https://ollama.ai/library)
* [Nvidia Container Toolkit Installation Guide](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html#installation)
* [Ollama Webui GitHub Repository](https://github.com/ollama-webui/ollama-webui)
This complete-ish guide provides a step-by-step approach to setting up and running Llama 2 (and other LLMs) on your gaming laptop using Docker and the Ollama platform. If you encounter any issues or have suggestions, feel free to leave a comment. \
\
Have an awesome day!
---
## AWS - Host Static Website With S3 + Cloudfront + Route53
**Date:** 2023-05-07
**URL:** https://lorbic.com/aws-host-static-website-with-s3--cloudfront--route53/
**Description:** In this blog learn how to host a static website on AWS with S3, Cloudfront and Route53. Enable HTTP/2, HTTP/3 and reditect insecure http to secure https. Set the bucket to private.
In this blog I'll discuss how to host a static website on AWS with S3, CloudFront and Route 53. We will secure our website with SSL certificate generated from Certificate Manger, enable HTTP/2 and HTTP/3 and redirect insecure http traffic to https version of the website. We will also make our bucket private and add policy to allow access from CloudFront.

In a later blog I will also setup GitHub actions to automatically deploy the website when we create a new post.
### GOALS:
1. Create S3 bucket.
2. Create CloudFront distribution.
3. Point CloudFront to s3 bucket and restrict bucket access to CloudFront only.
4. Add your domain (optional).
***NOTE: Replace \`example.org\` with your actual domain name.***
# Create S3 bucket
Open AWS console and got to S3 dashboard. Then create a new bucket with name as \`example.org\`.\
Go to **Properties** tab and enable **Bucket Versioning.** By enabling bucket versioning you will not lose previous version of your assets (static files).\
Go to **Permissions** tab and enable **Block public access (bucket settings)**, this will prevent access to the bucket from the public. Remember, goal #2 we will use CloudFront to deliver the assets.
# Create CloudFront distribution
Now we will create the CloudFront distribution and point it to our S3 bucket.\
In *CloudFront Dashboard* create a new CloudFront distribution.\
**Origin > Origin Domain,** select your S3 bucket.\
**Origin > Origin Access,** Select **origin access control settings** and select **Create Control Settings** and fill the following details.
> *Name:* leave it default or update\
> *Description (Optional):* add a description\
> *Signing Behavior:* Sign requests\
> *Origin Type:* S3
Then click create and select this newly created settings from the **origin access control** drop-down.\
(We will need to update our bucket's policy to allow CloudFront access to the bucket. We will do this later.)
In the **Web Application Firewall (WAF),** select `Do not enable security protections`\
At the very bottom, in the *Settings section* set **Default root object** to `index.html`. If we do not this we will see a sweet *access denied error.* Because we are allowing access to all the files inside our bucket **YOUR_BUCKET_NAME/** but not the bucket itself. So when we visit CloudFront distribution URL (e.g. `https://dfi9s7i5typ2c.cloudfront.net/`) CloudFront will not know what does `/` means. And when we set the default root object, CloudFront will know `/` means `/index.html` and it will load the index.html file.
Leave everything else as default, scroll down to bottom and click **Create Distribution.**
**Note: It will take 5-10 minutes to fully deploy the CloudFront distribution.**
# Configure bucket access
Open S3 Dashboard, go to **Permissions** tab. Select **Edit** on the *bucket policy* section and paste the following policy in the text block. This will allow CloudFront to access the objects while keeping the bucket private.
Replace the **YOUR_BUCKET_NAME**, **YOUR_ACCOUNT_ID** and **YOUR_CLOUDFRONT_DISTRIBUTION_ID** placeholders with correct values and save the policy.
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::YOUR_ACCOUNT_ID:distribution/YOUR_CLOUDFRONT_DISTRIBUTION_ID"
}
}
}
]
}
```
That's it, your website is live at your CloudFront distribution URL. You can find the URL on the home page of your distribution.\
If you are seeing some DNS error, then wait for some time.\
**Note: It will take 5-10 minutes to fully deploy the CloudFront distribution.**
Now, we will add a custom domain in our distribution.
# Custom Domain (Optional)
## Add Domain to Route 53
To complete this step you will need an existing domain or need to purchase a new one.\
Go to Route 53 dashboard and create a hosted zone (it will incur charges) and add your custom domain. Then go to your domain registrar and update the nameserver records, this will make Route 53 your DNS manager.\
It will take up to 24 hours to fully propagate the DNS. You can check the status on .
## Create SSL certificate
Open **Certificate Manager**, request a new certificate. Add your domain name and update your DNS records to validate the ownership.
Keep in mind to add both the root domain (example.org) and the wildcard domain (*.example.org).
## Add the domain to CloudFront
To add the domain, go to CloudFront Dashboard and select **Edit** under **General > Settings.** In the *Settings* section, update `Alternate domain name (CNAME)` and add your domain name. In `Custom SSL certificate` select your newly created SSL certificate. \
To point this domain to CloudFront. Open to your domain settings (*in R*oute *53*), click on **Create Record** and create an `A` record. Toggle the **Alias** button and in the *Route Traffic To* select your CloudFront distribution.\
In the same section enable HTTP/2 and HTTP3.
After some time (5-10 minutes) your website will be available at your domain address.\
\
Thanks for reading.\
If you have any questions, leave a comment below or drop an email at vikash\[at]lorbic\[dot]com.\
\
Have a nice day.
---
## Simplifying Search Activation: A Quick Guide with JavaScript
**Date:** 2023-04-01
**URL:** https://lorbic.com/simplifying-search-activation-a-quick-guide-with-javascript/
**Description:** Learn how to enhance user experience by activating the search input field with a simple key press on your website. This quick guide provides a code snippet and easy-to-follow steps.
Learn how to enhance user experience by activating the search input field with a simple key press on your website. This quick guide provides a code snippet and easy-to-follow steps.
### 1. HTML Markup for Search Input:
```html
```
### 2. JavaScript Functionality:
Activate the search input field by pressing a key (in this example, the '/' key). Modify the key binding according to your preferences.
```javascript
// app.js (app.min.js)
function handleSearchActivation(event, searchInput, searchButton) {
let KEY_TO_ACTIVATE_SEARCH = '/';
if (event.key === KEY_TO_ACTIVATE_SEARCH) {
searchInput.focus();
searchInput.value = "";
searchButton.click();
console.log("Pressed '/' to activate search.");
}
}
window.onload = function () {
console.log("Document loaded...");
let searchInput = document.querySelector("#search-input");
let searchButton = document.querySelector("#search-button");
document.addEventListener("keyup", (event) => {
handleSearchActivation(event, searchInput, searchButton);
});
};
```
### 3. Link the Script File in Your HTML:
Include the JavaScript file in the head or footer of your HTML. Alternatively, copy and paste the code into an existing JS file to reduce file requests.
```html
...
...
```
### 4. Customize UI:
You can also tailor the UI of the search input to match your preferences.\
\
Now, users can effortlessly activate the search input by pressing a key and start typing. You can also add a submit button and press 'Enter' to initiate the search.\
\
Thanks for Simplifying Your User's Experience!
---
## Setting Up a PostgreSQL Container: A Quick Guide
**Date:** 2023-04-01
**URL:** https://lorbic.com/setting-up-a-postgresql-container-a-quick-guide/
**Description:** Learn the simple and fast process of creating a PostgreSQL container using Docker. This guide provides both the command and a detailed explanation of the container and PostgreSQL database configuration.
Learn the simple and fast process of creating a PostgreSQL container using Docker. This guide provides both the command and a detailed explanation of the container and PostgreSQL database configuration.
## 1. Create the PostgreSQL Container:
```shell
docker run -d --name postgres \
-e POSTGRES_PASSWORD=RunningFlying2 \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v postgres_data:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:latest
```
## **2. Explanation:**
The above command initiates the creation of a container with the latest version of PostgreSQL. Here's a breakdown of the parameters used:
`-d: Runs the container in detached mode.`
`--name postgres: Assigns the name "postgres" to the container.`
`-e POSTGRES_PASSWORD=RunningFlying2: Sets the PostgreSQL user password to "RunningFlying2".`
`-e PGDATA=/var/lib/postgresql/data/pgdata: Specifies the PostgreSQL data directory.`
`-v postgres_data:/var/lib/postgresql/data: Creates a Docker volume named "postgres_data" for persistent data storage.`
`-p 5432:5432: Maps the container's 5432 port to the host machine's 5432 port for external access.`
`postgres:latest: Pulls and uses the latest version of the PostgreSQL image.`
## 3. Technical Details:
```
Container Name: postgres
Docker Volume: postgres_data
Host: 127.0.0.1
Port: 5432
User: postgres
Password: RunningFlying2
```
You have successfully set up a PostgreSQL container, ready to handle your database needs. The provided technical details ensure you can seamlessly connect to this container from your development or production environment.
**Explore More:**
Feel free to explore additional PostgreSQL configurations and features to tailor the container to your specific requirements.
> **Note:** For enhanced security, consider changing default passwords in production environments.
Have an amazing day.
---
## Learn Dart Programming
**Date:** 2021-05-12
**URL:** https://lorbic.com/learn-dart-programming/
**Description:** Learn basics of Dart programming language with code examples and explainations.
Good Evening,
Here are the Hands-on notes for Dart Programming Language.
I created these notes when I was learning Dart Language. So, these notes might help you too.
You can use these notes as a quick reference to Syntax and Demo.
I've covered almost every fundamental concept of Dart in this article.

Photo by Birmingham Museums Trust
---
# 1. Basics
## 1.1 The Main Function
Every Dart program starts execution from `main()` functions.
### The syntax of main function
_We use this version when we want to use command line arguments._
```dart
void main(List args){
// do your stuff here
}
```
Or simple version
_Generally we use this version of main._
```dart
void main(){
// do your stuff here
}
```
### Demo
```dart
void main() {
// say hello world
print("Hello World!");
// print some numbers, integer expression
print(1 * 2 + 34 - 12 / 5);
// print double
print(2.53);
// boolean
print(true);
}
```
---
## 1.2 Data Types
Literals in Dart.
```dart
// literals in Dart
"Dan"; // String literal
23; // int literal
45.6; // double literal
true; // bool literal
```
There are 4 built-in data types in Dart.
| SN | Data Type | Description |
| --- | --- | --- |
| 1. | int | Integer value |
| 2. | double | Floating point value |
| 3. | String | String value |
| 4. | bool | `true` , `false` value |
### Syntax creating variables in Dart
**Use explicit way to declare the variable.**
`typename variable_name;`
Or initialize while creating.
`typename variable_name = initial_value;`
```dart
int intVariable;
int anotherIntVariable = 111;
String name = "Vikas";
double pi = 3.14;
bool isdeveloper = true;
```
**Use implicit way to declare the variable.**
Use `var` to create any type of variable.
`var variable_name;`
Or initialize while creating.
`var variable_name = intial_value`;\`
### Demo
**Note: _In Dart all the data types are objects and their initial value is `null`._**
Create the variables
```dart
// numbers: int
int score = 90;
// store hexadecimal value
int hexValue = 0xEAEAEA;
// numbers: double
double length = 24.6;
double exponentValue = 1.4e5;
// String
String name = "Dave";
// boolean
bool going = false;
// use var
var name2 = "Vikas"; // String
var age = 20; // int
var score2 = 45.6; // double
var isHere = true; // bool
var exp = 2.5e6; // exponential (double)
var hex2 = 0xEC43AB; // hex (int)
var data; // will have null
```
Print the values
```dart
print(score); //int
print(hexValue); //int
print(length); //double
print(exponentValue);//double
print(going); //bool
print(name); //String
print(name2); //String
print(age); //int
print(score2); //int
print(isHere); //bool
print(exp); //double
print(hex2); //int
print(data); //null value
```
---
## 1.3 String and String Interpolation
Ways to define a String variable
```dart
// ways to define string
String s1 = 'Vikas'; // with single quote
String s2 = "Dave"; // with double quote
String s3 = "It's Easy"; // can use both
String s4 = 'It\'s Easy'; // excape sequence
String s5 = 'This is a very very long string '
'and exceeding the line.'; // long string
// auto concatenation of strings
```
String Interpolation
```dart
// Normal Concatenation
String name = "Vikas";
String msg = name + ", We are heading to the west";
// Interpolation
String msg2 = "$name We are heading to the west";
String msglen = "Length of msg = ${msg2.length}";
// Print
print(msg2);
print(msglen);
```
We can interpolate any data type with String in `print(...)` using `$varname`.
```dart
int BoxLength = 123;
double BoxWeight = 4522.4545;
print("Length of box = $BoxLength \nWeight of Box = $BoxWeight");
```
---
## 1.4 Constant and Final Variables
In dart we can create constants using
-> final
-> const
1. **final vs const:**
- `final` variable can only be set once and it is initialized when accessed
- `const` is internally final in nature but it is a `compile-time constant`
-> i.e. it is initialized during compilation
2. Instance variable can be final but cannot be constant
3. If you want a Constant class level then make it
`static const` .
### Demo
```dart
void main() {
// final
final city = "Toronto";
// or
// final String city = "Toronto";
// city = "NY"; // Error: Can't assign to the final variable 'city'.
const PI = 3.1415;
const double gravity = 9.8;
}
```
Class level constant
```dart
class Circle {
final color = "RED"; // OK
// const PI = 3.1415; // Not OK
static const PI = 3.1415; // OK
}
```
**Only static fields can be declared as `const`.**
**Try declaring the field as `final`, or adding the keyword `static`.**
---
# 2. Control Statements
These statements are use to control the execution flow of the program and add various logics to the program.
## 2.1 If - Else Statements
Simple condition checking.
**Syntax**
#### IF alone
```dart
if(condition){
// block 1
// execute the code
}
```
When the condition is `true` the code inside `block 1` gets executed.
Otherwise nothing happens to the code inside `block 1`.
#### IF and ELSE together
```dart
if(condition){
// block 1
// execute the code
} else{
// block 2
// execute the code
}
```
#### IF-ELSE ladder
```dart
if(condition){
// block 1
// execute the code
} else if(condition2){
// block 2
// execute the code
} else if(condition3){
// block 3
// execute the code
}
.
.
.
else if(condition n){
// block n
// execute the code
} else{
// block last
// execute the code
}
```
When the condition is `true` the code inside the respective `block` gets executed. Otherwise `block last` is executed.
### Demo
```dart
void main() {
var salary = 250000;
if (salary > 200000) {
print("You, can get the Credit Card");
} else if (salary > 150000) {
print("You can apply for the Credit Card");
} else {
print("You cannot get the Credit Card");
}
}
```
Check code inside `01 basics/05if_else.dart`.
---
## 2.2 Conditional Expression
Conditional expression is a simple alternative to `if-else`.
There are two conditional expressions
1. **`condition ? expr1 : expr2;`**
returns `expr1` if condition is true else returns `expr2`
```dart
int a = 12, b = 45;
print("Small Number = ${(a < b) ? a : b}");
int c = (a < b) ? a : b;
print("Small Number = $c);
```
2. **`expr1 ?? expr2`**
if `expr1` is not-null, returns its value; otherwise, evaluates and returns the value of `expr2`
```dart
int x, y = 345; // x = null;
print("Value = ${x ?? y}");
int z = x ?? y;
print(z);
```
---
## 2.3 Switch Case
If we have constant conditions like ids as `1, 2, 3, 4, 5`
Instead using many `if-else` statements we can use `switch-case` statement.
The case can be a constant `int` or a constant `String`.
#### Syntax
```dart
switch(variable){
case 1:
// code
break; // this is must
case 2:
// another code
break;
default:
// will execute if no case matches
}
```
`break` is must to stop execution after every `case`.
### Demo
With integer cases.
```dart
// Integer (int)
var option = 2;
switch (option) {
case 1:
print("Option 1");
break;
case 2:
print("Option 2");
break;
default:
print("Invalid option");
}
```
With String cases.
```dart
String name = "Andy";
switch (name) {
case "Andy":
print("Hello, Andy");
break;
case "Dave":
print("Hello, Dave");
break;
default:
print("No name");
}
```
---
# 3. Looping
We can repeat the statements using looping.
There are 3 loops in Dart :
- For
- While
- Do ...While
## 3.1 For loop
1. The loop first initializes the `iteration_var`
2. then checks `breaking_condition`
3. then executes the `Statements` and
4. increments or decrements the `iteration_var` and
5. 2,3,4, are repeated until `breaking_condition` remains `true`.
### Syntax
```dart
for(iteration_var; breaking_condition; increment/decrement)
{
// Statements
}
```
### Demo
```dart
// print even nums
for (var i = 1; i <= 10; i++) {
if (i % 2 == 0){
print(i);
}
}
```
### 3.1.1 For ... in Loop
#### Syntax
`for(var varname in IterableList){....}`
#### Demo
```dart
// for ..in loop
List names = ["Dave", "Andy", "Vikas", "Mark"];
for (var name in names) {
print(name);
}
```
This loop is very useful when using List and other data containers.
### 3.1.2 Variation in for
we can omit the `initial`, `breaking` and `incr/decr` statements.
```dart
for (; x < 20; x++) {
print(x);
}
for(;;x++){
print(x);
if(x==10){
break;
}
}
for(var x = 0;;){
x++;
print(x);
if(x==10){
break;
}
}
```
---
## 3.2 While Loop
While loop is an `entry controlled` loop.
The code inside `{...}` of while loop will execute only when the condition is `true`.
### Syntax
`while(condition){...}`
Here we declare a condition or breaking condition for the loop.
See the demo
### Demo
```dart
// while loop
// print 0...9
var k = 0; // this is must
while (k < 10) {
print(k);
k++;
}
```
---
## 3.3 Do ...While Loop
Do ...while Loop is an `exit controlled` loop.
Here the `Statement` will run for the first time regardless the `condition` is `true` or `false`.
Then it will check the `condition` if it is `true` the the loop will continue execution otherwise it will jump out of the loop.
### Syntax
`do{...} while(conditon);`
Here the semicolon(`;`) is must.
### Demo
```dart
// print 0...9
// do ..while loop
int x = 0;
do {
print(x);
x++;
} while (x < 10);
```
### While vs Do...While
Both work in similar manner.
But, `do...while` will execute at least once and `while` won't.
---
## 3.4 Break and Continue
These are two loop control statements.
Which are used to _forcefully control_ the flow of loop execution.
### Break
`break` is used to stop the execution, and jump out of the loop.
#### Demo
```dart
// break after printing 5
for(int i = 0; i < 10; i++){
print(i);
if(i==5){
break;
}
}
// run and observe
// break -> stop execution of loop
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
print("$i $j");
if (i == 2 && j == 2) {
break; // will break inner loop
}
}
}
```
**We have already used `break` in `switch...case` program above.**
### Continue
`continue` is used to skip current iteration.
#### Demo
```dart
// continue -> skip an iteraion in a loop
for (var i = 0; i < 10; i++) {
if (i == 5) {
// skip when i==5
continue;
}
print(i);
}
```
---
## 3.5 Label
Label is a new concept in Dart (we have seen it in `C` language with its buddy `goto`).
This is not a magical spell from _Hogwarts_ that will do amazing magical things.
It is just a way to make loop more controlled than before.
We can name a block of code using label.
Take a look at below code snippet.
### Demo
```dart
print("i j");
outerLoop:
for (int i = 0; i < 5; i++) {
// ignore: unused_label
innerloop:
for (int j = 0; j < 5; j++) {
print("$i $j");
if (i == 2 && j == 2) {
break outerLoop; // will break outerloop
}
}
}
```
Try doing this and observe the result of `i j`.
```dart
print("i j");
outerLoop:
for (int i = 0; i < 5; i++) {
// ignore: unused_label
innerloop:
for (int j = 0; j < 5; j++) {
print("$i $j");
if (i == 2 && j == 2) {
break innerLoop; // will break innerloop
}
}
}
```
---
# 4. Functions
Functions are used to group the code statements that do something.
e.g. You want to calculate the area of a rectangle then the formula will be `area = length * width`.
You can do it where you want to use the `area`. _But, if you want to double the area and add 20 to the result then what ? _
_Will you write all the code again and again or find some convenient solution._
So, the solution is using functions.
Your code will be
```dart
var area = length * width;
area = area * 2;
area = area + 20;
```
Now you are able to use the final value of `area`.
So, let's declare a simple function that says `Hello World!` to the user (after learning the simple function we will continue with our `area` calculation)
```dart
void sayHello(){
print("Hello World!");
// That's common saying hello to the world
// let's say 'Hello Dart, Welcome to Earth'
print("Hello Dart, Welcome to Earth");
}
```
## 4.1 Breakdown of function (Syntax)
**`void`** : It is the return type as you know Dart is a statically typed language like Java, C++ and C. This tells the compiler that we will return a value of the given type `(int, double, String, bool, other user defined types)`.
Here `void` tells that the function will not return any value.
**`sayHello`** : It is the name of the function. It can be anything but, should be relevant to the work of the function like: `multiplyBy2(), makeHalf(), doubleThevalue(), reduceThree(), calculateSI() etc.`
**`()`** : It is called parameter. we can pass values that we want to work on. Like a `name` that should be printed instead of `Dart` or `World` in the above example.
Let's assume we want to say Hello to you and we don't know your name then we will pass a `String` called `name` and interpolate it with the word `Hello` and print it.
Look at the code below..
```dart
void sayHello(String name){
print("Hello, $name");
}
void main(){
sayHello("Vikas"); // Hello, Vikas
sayHello("Dart"); // Hello, Dart
sayHello("World"); // Hello, World
}
```
Copy the above code and run it.
You can also return the string.
```dart
String sayHello(String name){
return "Hello, $name";
// don't forget to change the return type
}
void main(){
print(sayHello("Vikas")); // Hello, Vikas
print(sayHello("Dart")); // Hello, Dart
print(sayHello("World")); // Hello, World
}
```
Now, let's work on our `area` example:
```dart
int smartAreaOfRectange(int length, int width) {
int area = length * width;
area = area * 2;
area = area + 20;
return area;
}
```
Put this code in your file and call it in the main function as we've done in `sayHello(...)` function.
Another Example:
```dart
int doubleIt(int x) {
return x * 2 + 17;
}
void main() {
for (int i = 1; i <= 10; i++) {
print(doubleIt(i));
}
}
```
---
## 4.2 Function Expression (Fat Arrow `=>`)
The function expression or _Fat Arrow `=>`_ is used to make the function definition shorter and simpler.
**It can only be used when there is only one statement in the function.**
Like , double the value
```dart
int doubleIt(int x) => x*2;
```
we don't use the `return` keyword here.
So ,
```dart
int doubleIt(int x) => return x*2;
```
will be wrong.
---
## 4.3 Types of function parameters
PARAMETERS:
- Required
- Optional:
- Positional
- Named
- Default:
- Positional
- Named
### 4.3.1 Required Parameters
These are the required parameters that cannot be omitted.
```dart
// required parameters
void requiredParameters(String c1, String c2, String c3) {
print("Required Parameters");
print("$c1, $c2, $c3");
}
void main() {
// required parameters
requiredParameters("NY", "Toronto", "San Diego");
}
```
### 4.3.2 Optional Parameters
We can omit passing these parameters.
Blank value is considered as `null`.
#### 4.3.2.1 Optional Positional Parameters
We pass the value based on the portion of the parameter in the function.
These parameters are surrounded by brackets `[ ... ]`.
```dart
// optional positional parameters
void optionalPositionalParameters(String c1, String c2, [String c3]) {
print("Optional Positional Parameters");
print("$c1, $c2, $c3");
}
void main() {
// optional positional parameters
optionalPositionalParameters("NY", "Toronto"); // 2 values
optionalPositionalParameters("NY", "Toronto", "San Diego"); // 3 values
}
```
#### 4.3.2.2 Optional Named Parameters
we can give the name of parameter while passing the value.
These parameters are surrounded by braces `{ ... }`.
```dart
// optional named parameters
void optionalNamedParameters(String c1, String c2, {String c3}) {
print("Optional Named Parameters");
print("$c1, $c2, $c3");
}
void main() {
// optional named parameters
optionalNamedParameters("NY", "Toronto");
optionalNamedParameters("NY", "Toronto", c3: "San Diego");
}
```
#### 4.3.2.3 Default Parameters
These are the `positional and named` parameters with default value.
**Default Positional**
We pass the default value of the Positional Parameter while defining the function `[String name = "Dart", int id = 1111]`.
```dart
// default positional parameters
void defaultPositionalParameters(String c1, String c2, [String c3 = "Mumbai"]) {
print("deafault positional Parameters");
print("$c1, $c2, $c3");
}
void main() {
// default positional
defaultPositionalParameters("NY", "Toronto");
defaultPositionalParameters("NY", "Toronto", "San Diego");
}
```
**Default Named**
We pass the default value of the Named Parameter while defining the function `{String name = "Dart", int id = 1111}`.
```dart
// default named parameters
void defaultNamedParameters(String c1, String c2, {String c3 = "Mumbai"}) {
print("default Named Parameters");
print("$c1, $c2, $c3");
}
void main() {
// default named
defaultNamedParameters("NY", "Toronto");
defaultNamedParameters("NY", "Toronto", c3: "San Diego");
}
```
---
# 5. Exception Handling
_What are exceptions ?_
An **Exception** is a runtime error which occurs when the program is running due to some error that the compiler was unable to detect.
If an exception occurs the program crashes.
If not handled may cause serious issues.
Below table showing some exceptions in Dart
| S.N. | Exception | Description |
| --- | --- | --- |
| 1. | DeferredLoadException | Thrown when a deferred library fails to load. |
| 2. | FormatException | Exception thrown when a string or some other data does not have an expected format and cannot be parsed or processed. |
| 3. | IntegerDivisionByZeroException | Thrown when a number is divided by zero. |
| 4. | IOException | Base class for all Input-Output related exceptions. |
| 5. | IsolateSpawnException | Thrown when an isolate cannot be created. |
| 6. | Timeout | Thrown when a scheduled timeout happens while waiting for an async result. |
## 5.1 Example of Exception
Simplest example will be dividing a number by _Zero_.
```dart
void main(){
// integer division
int result = 12 ~/ 4; // OK
int badResult = 15 ~/ 0; // NOT OK
}
```
So, the line `double badResult = 15 / 0;` raises an `IntegerDivisionByZeroException` exception.
## 5.2 Handling of Exception
We can handle the exceptions by surrounding the exception occurring code inside a `try` block.
And handle the exception using `on`, `catch`, and `finally` blocks.
### 5.2.1 Try Block
This is the place where we write an exception occurring statement.
#### Demo
```dart
try {
int answer = 12 ~/ 0;
print("Division = $answer");
}
```
If the statement inside `try` block raises an exception the program will not crash this time instead it will throw the exception out of the `try` block which we'll have to catch.
### 5.2.2 On Block
We can use `on` to catch the exception _if we know the thrown exception._
```dart
// CASE1: Handle with "on"
// use on when we know the exception
try {
int answer = 12 ~/ 0;
print("Division = $answer");
} on IntegerDivisionByZeroException {
print("Cannot divide by zero");
}
```
Here we know the thrown exception `IntegerDivisionByZeroException`.
### 5.2.3 Catch Block
If we don't know the exception we can simply catch it using `catch` block.
```dart
// CASE2: Handle with "catch"
// use catch(e) when we don't know the exception
try {
int answer = 12 ~/ 0;
print("Division = $answer");
} catch (e) {
print("The exception : $e");
}
```
Here the unknown exception is successfully handled.
### 5.2.4 Stack Trace
We can use the Stack Trace to find the events that threw the exception.
```dart
// CASE3: using STACK TRACE to know the events occured
// before exception was thrown
try {
int answer = 12 ~/ 0;
print("Division = $answer");
} catch (e, stackTraceObject) {
print("The exception : $e");
print("Stack Trace:\n$stackTraceObject");
}
```
### 5.2.5 Finally Block
This Block is always executed regardless the occurance of the exception.
**No exception:**
```dart
// CASE4: finally clause
try {
int answer = 12 ~/ 4;
print("Division = $answer");
} catch (e, stackTraceObject) {
print("The exception : $e");
print("Stack Trace:\n$stackTraceObject");
} finally {
print("This will always execute No exception)");
}
```
**With Exception:**
```dart
// CASE4: finally clause
try {
int answer = 12 ~/ 0;
print("Division = $answer");
} catch (e, stackTraceObject) {
print("The exception : $e");
print("Stack Trace:\n$stackTraceObject");
} finally {
print("This will always execute (With exception)");
}
```
## 5.3 Custom Exception
**Q. Can we have our iwn exceptions ?**
**A. Yes, we can define our own exception class using the following method.**
First create a class with `YourCustomExceptionName` and _implement_\* the built-in `Exception` class.
Then _override_ the `errorMessage()` method to display "Your custom error message".
\*_We will learn about Object Oriented Programming later in the article._
#### Demo
```dart
// custom exception class
class DepositAmountLessThanZeroException implements Exception {
String errorMessage() {
return "Ammount cannot be less than 0";
}
}
```
Let's use the custom exception class.
Create a function which throws the exception.
```dart
void depositMoney(int amount) {
if (amount < 0) {
throw new DepositAmountLessThanZeroException();
} else {
print("Successful, Deposited $amount");
}
}
```
Now call the function in the try block.
```dart
void main() {
// OK
try {
depositMoney(1500);
} catch (e, s) {
print(e.errorMessage());
print(s);
}
// OK
try {
depositMoney(0);
} catch (e, s) {
print(e.errorMessage());
print(s);
}
// Exception
try {
depositMoney(-1233);
} catch (e, s) {
print(e.errorMessage());
print(s);
}
}
```
That's all from my side on basic exception handling.
We will discuss the topic in detail later in another blog.
Thanks for reading. 🙏
If you liked it feel free to share with your dear ones.💗
And tell me what do you think in the comment box.💬
Stay tuned.
---
## Types of Pointers in C/C++
**Date:** 2021-05-12
**URL:** https://lorbic.com/types-of-pointers-in-c/c/
**Description:**

Photo of _Hyacinth macaw by_ Roi Dimor on [Unsplash](https://unsplash.com/photos/AEQ-166CWY8)
---
# Types of Pointers in C / C++
## 1. Null Pointer
It is a pointer pointing to nothing. **NULL** pointer points to the base address of the segment.
`-EXAMPLE-`
```c
int * ptr = (int) * 0;
float * fptr = (float) * 0;
double * dptr = (double) * 0;
char * chptr = (char) * 0;
```
##### Other ways of initializing NULL pointer
```c
int * ptr = NULL;
char * chptr = '\0';
```
> #### NULL also means 0 in macro
>
> ```c
> #define NULL 0
> ```
---
## 2. Dangling Pointer
A pointer pointing to the memory address of any variable (or object) which has been deleted from memory.
When a pointer points to a deleted memory address, the pointer is called as a _dangling pointer_.
`-EXAMPLE-`
```cpp
Person p = new Person();
Person * pptr = &p;
delete p;
/* here pointer pptr (* pptr) is still pointing to
the Person object which has been deleted.
*/
```
---
## 3. Generic Pointer
_void_ pointer is known as generic pointer. It can point to **_any type_** of data.
`-EXAMPLE-`
```cpp
void * ptr;
```
#### Points to remember
- We can't de-reference a generic pointer.
- We can find the size of pointer using `sizeof()` operator.
- These pointers can hold any type of pointer such as char, int, float, structure, array, object etc without any typecasting.
- Any type of pointer can hold generic pointer without typecasting.
- Generic pointer can be used to implement dynamic datatype.
---
## 4. Wild Pointer
A pointer which has not been initialized is called as _wild pointer_.
`-EXAMPLE-`
```cpp
int * ptr;
```
---
## 5. Complex Pointers
These are pointers pointing to derived data-types.
- Pointer to array
- Pointer to function
- Pointer to structure / union
- Pointer to object
- Multilevel pointers
---
## 6. near / far / huge Pointers
These pointer modifiers were used in 1980's-90's before 32 bit architecture.
**_near_** : a 16 bit pointer that can address any byte in a 64k segment.
**_far_** : a 32 bit pointer that contains a segment and an offset.
**_huge_** : a 32 bit pointer in which the segment is "normalized" so that no two far pointers point to the same address unless they have the same value.
You can read this stack overflow answer for more information.
---
Thanks for reading. 🙏
If you liked it feel free to share with your dear ones.💗
And tell me what do you think in the comment box.💬
Stay tuned.
---
---
## Avoid Memory Leaks In C++
**Date:** 2021-05-04
**URL:** https://lorbic.com/avoid-memory-leaks-in-c/
**Description:**
**Instructions**
Things You'll Need
- Proficiency in C++
- C++ compiler
- Debugger and other investigative software tools
# Part 1
Understand the operator basics. The C++ operator `new` allocates heap memory. The `delete` operator frees heap memory. For every `new`, you should use a `delete` so that you free the same memory you allocated:
```cpp
char* str = new char [30]; // Allocate 30 bytes to house a string.
delete [] str; // Clear those 30 bytes and make str point nowhere.
```
# Part 2
Reallocate memory only if you've deleted. In the code below, `str` acquires a new address with the second allocation. The first address is lost irretrievably, and so are the 30 bytes that it pointed to. Now they're impossible to free, and you have a memory leak:
```cpp
char* str = new char [30]; // Give str a memory address.
// delete [] str; // Remove the first comment marking in this line to correct.
str = new char [60]; /* Give str another memory address with the first one gone forever.*/
delete [] str; // This deletes the 60 bytes, not just the first 30.
```
# Part 3
Watch those pointer assignments. Every dynamic variable (allocated memory on the heap) needs to be associated with a pointer. When a dynamic variable becomes disassociated from its pointer(s), it becomes impossible to erase. Again, this results in a memory leak:
```cpp
char* str1 = new char [30];
char* str2 = new char [40];
strcpy(str1, "Memory leak");
str2 = str1; // Bad! Now the 40 bytes are impossible to free.
delete [] str2; // This deletes the 30 bytes.
delete [] str1; // Possible access violation. What a disaster!
```
# Part 4
Be careful with local pointers. A pointer you declare in a function is allocated on the stack, but the dynamic variable it points to is allocated on the heap. If you don't delete it, it will persist after the program exits from the function:
```cpp
void Leak(int x){
char* p = new char [x];
// delete [] p; // Remove the first comment marking to correct.
}
```
# Part 5
Pay attention to the square braces after "delete". Use `delete` by itself to free a single object. Use `delete []` with square brackets to free a heap array. Don't do something like this:
```cpp
char* one = new char;
delete [] one; // Wrong
char* many = new char [30];
delete many; // Wrong!
```
---
_**Keep Learining, Keep Practicing. :) :)**_
---
That's All. 😅
Thanks for reading. 🙏
If you liked it feel free to share with your dear ones.💗
And tell me what do you think in the comment box.💬
Stay tuned with CS111.
---
## Operators in Bash Shell Programming
**Date:** 2021-05-04
**URL:** https://lorbic.com/operators-in-bash-shell-programming/
**Description:**

Photo by [NASA](https://unsplash.com/photos/-5V6VZxSQRo) on Unsplash
---
If you want to learn bash bash scripting please read this article.
[Learn complete Linux bash (shell) scripting in one article](/post/learn-complete-linux-bash-scripting-in-one-article/)
Operators help us perform various types of operations such as addition, multiplication etc.
There are following types of operators present in bash:
- Arithmetic,
- Relational,
- Boolean,
- File Test,
- String Test
## 1. Arithmetic Operators
All the arithmetic operators present in bash are discussed below with examples.
These operators work with integers.
#### 1.1 Addition Operator
It's a **`+`** that adds operands together.
Shown in the below example:
```bash
$x=20
$y=30
a=`expr $x + $y`
echo $a
```
This will display:
> 50
##### NOTE:
> 1. The **`expr `** command evaluates the expression.
> 2. There is `` before and after the **`+`** operator .
#### 1.2 Subtraction Operator
It's a **`-`** that subtracts second operand from first operand.
Shown in the below example:
```bash
$x=40
$y=30
a=`expr $x - $y`
echo $a
```
This will display:
> 10
#### 1.3 Multiplication Operator
It's a **`*`** that multplies operands together.
Shown in the below example:
```bash
$x=2
$y=3
a=`expr $x * $y`
echo $a
```
This will display:
> 6
#### 1.4 Division Operator
It's a **`/`** that performs division operation.
Shown in the below example:
-Example 1-
```bash
$x=200
$y=50
a=`expr $x / $y`
echo $a
```
This will display:
> 4
-Example 2-
```bash
$x=20
$y=3
a=`expr $x / $y`
echo $a
```
This will display:
> 6
#### 1.5 Modulus Operator
It's a **`%`** that performs modulus operation and returns the remainder.
Shown in the below example:
```bash
$x=10
$y=3
a=`expr $x % $y`
echo $a
```
This will display:
> 1
#### 1.6 Equality Check Operator
It's a **`==`** that performs equality check operation and returns 1 if both sides are equal otherwise returns 0.
Shown in the below example:
-Example 1-
```bash
$x=10
$y=10
a=`expr $x == $y`
echo $a
```
This will display:
> 1
-Example 2-
```bash
$x=10
$y=5
a=`expr $x == $y`
echo $a
```
This will display:
> 0
#### 1.7 Not Equal Check Operator
It's a **`!=`** that performs equality check operation and returns 0 if both sides are equal otherwise returns 1.
Shown in the below example:
-Example 1-
```bash
$x=10
$y=10
a=`expr $x == $y`
echo $a
```
This will display:
> 0
-Example 2-
```bash
$x=10
$y=5
a=`expr $x == $y`
echo $a
```
This will display:
> 1
## 2. Relational Operators
Relational operators are used to perform comparison among given operands.
### -eq (Equals to operator)
This checks whether the operands are equal.
This operator is used to perform comparison in the `if` condition.
```bash
a=10
b=10
if [ $a -eq $b ]
then
echo "Equal"
else
echo "Not Equal"
fi
```
> Equal
### -ne (Not equals to operator)
This checks whether the operands are equal.
This operator is used to perform comparison in the `if` condition.
```bash
a=10
b=20
if [ $a -ne $b ]
then
echo "Not Equal"
else
echo "Equal"
fi
```
> Not Equal
### -gt (Greater than operator)
This checks whether the first operand is greater than the second operand.
This operator is used to perform comparison in the `if` condition.
```bash
a=40
b=20
if [ $a -gt $b ]
then
echo "$a is greater than $b"
else
echo "$a is not greater than $b"
fi
```
> 40 is greater than 20
### -lt (Less than operator)
This checks whether the first operand is less than the second operand.
This operator is used to perform comparison in the `if` condition.
```bash
a=20
b=40
if [ $a -lt $b ]
then
echo "$a is less than $b"
else
echo "$a is not less than $b"
fi
```
> 20 is greater than 40
### -ge (Greater than or equals to operator)
This checks whether the first operand is greater than or equals to the second operand.
This operator is used to perform comparison in the `if` condition.
```bash
a=40
b=20
if [ $a -ge $b ]
then
echo "$a is greater than or equals to $b"
else
echo "$a is not greater than $b"
fi
```
> 40 is greater than or equals to 20
### -le (Less than or equals to operator)
This checks whether the first operand is greater than or equals to the second operand.
This operator is used to perform comparison in the `if` condition.
```bash
a=40
b=200
if [ $a -le $b ]
then
echo "$a is less than or equals to $b"
else
echo "$a is not less than $b"
fi
```
> 40 is less than or equals to 200
## 3. Boolean Operators
### ! (Not operator)
This changes `true` into `false` and vice versa.
We have used this operator in _Not equal operator_ under arithmetic operators.
Shown in the below example:
-Example 1-
```bash
$x=10
$y=10
a=`expr $x == $y`
echo $a
```
This will display:
> 0
-Example 2-
```bash
$x=10
$y=5
a=`expr $x == $y`
echo $a
```
This will display:
> 1
### -o (OR operator)
Checks whether one of the operands is true and executes the statements.
```bash
a=40
b=20
c=10
if [ $a -gt $b -o $c -gt $b]
then
echo "$a or $c is greater than $b"
else
echo "$a is not less than $b"
fi
```
> 40 or 10 is greater than 20
### -a (AND operator)
Checks whether all of the operands are true and executes the statements.
```bash
a=40
b=20
c=100
if [ $a -gt $b -a $c -gt $b]
then
echo "$a and $c are greater than $b"
else
echo "$a is not less than $b"
fi
```
> 40 and 100 are greater than 20
## 4. String Test Operators
These operators are used to perform string related comparisons.
### = (Equality Operator)
Check whether two strings are equal.
```bash
user="VIKAS"
defaultUser="VIKAS"
if [ $user = $defaultUser ]
then
echo "User is allowed"
else
echo "User is not allowed"
fi
```
> User is allowed
### != (Not equal operator)
Check whether two strings are not equal.
```bash
user="VIKAS"
defaultUser="DAVE"
if [ $user != $defaultUser ]
then
echo "User is not allowed"
else
echo "User is allowed"
fi
```
> User is not allowed
### -z (Zero length string)
Checks whether the string is zero length.
```bash
s=""
if [ -z $s ]
then
echo "String is zero length"
else
echo "String is non zero length"
fi
```
> String is zero length
### -n (Non zero length string)
Checks whether the string is empty.
```bash
s="Village Programmer"
if [ -n $s ]
then
echo "String is non zero length"
else
echo "String is zero length"
fi
```
> String is non zero length
### Empty string check
```bash
s=""
if [ $s ]
then
echo "String is not empty"
else
echo "String is empty"
fi
```
> String is not empty
---
_**Keep Learining, Keep Practicing. :) :)**_
---
That's All. 😅
Thanks for reading. 🙏
If you liked it feel free to share with your dear ones.💗
And tell me what do you think in the comment box.💬
Stay tuned with CS111.
This post was originally posted on [Village Programmer](https://villageprogrammer.blogspot.com)
---
## Learn Complete Linux Bash Scripting in One Article
**Date:** 2021-05-04
**URL:** https://lorbic.com/learn-complete-linux-bash-scripting-in-one-article/
**Description:**

-- Photo by **[Iván Rivero](https://www.pexels.com/@osho?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels)** from **[Pexels](https://www.pexels.com/photo/tractor-with-trailer-under-cloudy-skies-during-day-745266/?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels)**
In this article I'll be discussing about linux bash scripting (shell scripting) and I will cover every fundamental concept that you need to get started with bash scripting under linux environment.
Bash scripting is a critical skill for every programmer.
First of all you will need a **linux machine** to execute these scripts.
You can use any of the below techniques to get a linux machine:
- Install a linux distribution
- Install WSL
- Install Cygwin or MSYS
- Installing _git for bash_ will provide a bash prompt but this prompt is not a complete linux environment
I'll suggest you to install **WSL2** with **Ubuntu-2020.04** (_same is installed on my machine_).
This one article will cover all the basics and some advanced concepts about bash (shell) scripting, so read it completely.
## Very Basics
### 1. Hello World
Every programmer start by writing a program to print _'Hello World'_ on the console.
Create a file named `hello.sh` and open it with your favourite text editor (notepad, sublime, atom, vscode, nano, vim, etc).
Write the following code into the file and save.
```bash
echo "Hello World :)"
```
Now run the script by using following command
```sh
$ bash ./hello.sh
```
This will print
> Hello World :)
### 2. Comments
We can write comments by using `#` symbol.
```bash
# This is a comment and will not be executed
# The below command will print "Hello World" to the console
echo "Hello World"
```
> Hello World
### 3. What is shebang (#! /bin/bash)
The **shebang is used** if you run the script directly as an executable file (for example with the command ./script.sh ). In this case it tells the operating system which executable to run. It's not required and has no effect if you for example write `bash ./script.sh` or source the script.
We write the below line at the top of every script
`#!/bin/bash`
or
`#!/usr/bin/env bash`
##### Hello World with shebang
```bash
#!/usr/bin/env bash
# hello.sh
echo "Hello World :)"
```
> Hello World :)
### 4. Variables
Creating variables in bash script is as simple as
```bash
name="Vikash"
```
**NOTE:** Remember there is no space around _=_ operator.
##### Hello World with variables
-- `hello2.sh` --
```bash
#!/usr/bin/env bash
msg="Hello World from a variable"
echo $msg
```
`$ ./hello2.sh`
> Hello World from a variable
### 5. Command line arguments
We can pass arguments while executing the script and use them in the script.
A simple example is below.
-- `params.sh`--
```bash
#!/usr/bin/env bash
name=$1
website=$2
echo "Hello I am $name"
echo "My website is $website"
```
`$ ./params.sh "Vikash" "Villageprogrammer.blogspot.com"`
> Hello I am Vikash
> My website is Villageprogrammer
| Parameter Name | Description |
| -------------- | ------------------------ |
| $0 | Script name and path |
| $1 | First argument |
| $2 - $9 | Second to ninth argument |
| ${10} - ${...} | More than tenth argument |
You can execute a standard linux command and store the result in the variable.
-- `params2.sh`--
```bash
#!/usr/bin/env bash
today=$(date)
directory=$(pwd)
echo "Today is : $today"
echo "Directory : $directory"
```
`$ ./params2.sh`
> Today is : Thu Feb 18 17:05:56 IST 202
> Directory : /mnt/d/Xplore-Training/UNIX/bash-scripting/scripting
## Controls
### 1. If statement
The syntax of if statement is similar to other programming languages like _C, C++_.
Syntax
```bash
if [ condition ]
then
# write your code here
fi
```
Example:
--`if.sh `--
```bash
#!/usr/bin/env bash
num=10
if [ $num -lt 20 ]
then
echo "$num is less than 20"
fi
```
`$ if.sh`
> 10 is less than 20
You can combine parameter and variable logic with if to write complex scripts.
### 2. if-else
Syntax
```bash
if [ condition ]
then
# write your code here
else
# write your code here
fi
```
Example:
--`if-else.sh `--
```bash
#!/usr/bin/env bash
num=10
if [ $num -eq 50 ]
then
echo "$num is equal to 50"
else
echo "$num is not equal to 50"
fi
```
`$ ./if-else.sh`
> 10 is not equal to 50
### 3. if-elif-else
Syntax
```bash
if [ condition ]
then
# write your code here
elif [ condition ]
then
# write your code here
fi
```
Example:
--`if-elif-else.sh `--
```bash
#!/usr/bin/env bash
num=10
if [ $num -eq 20 ]
then
echo "$num is equal to 20"
elif [ $num -lt 20 ]
then
echo "$num is less than 20"
else
echo "$num is greater than 20"
fi
```
`$ ./if-elif-else.sh`
> 10 is less than 20
## Looping
Repetition of a code block can be done using while loop and for loop.
### 1. while loop
Syntax
```bash
while [ condition ]
do
# write your code here
done
```
Example
-- `while.sh`--
```bash
count=1
while [ $count -lt 5 ]
do
echo $count
((count++))
done
```
`$ ./while.sh`
> 1
> 2
> 3
> 4
> 5
### 2. for loop
We can pass an array of elements from command line and use them in the script by creating an array
**`array=$@`**
Syntax:
```bash
for num in $container
do
echo $num
done
```
Example:
--`for.sh`--
```bash
#!/usr/bin/env bash
nums=$@
for num in $nums
do
echo $num
done
```
`$ ./for.sh 1 2 3 `
> 1
> 2
> 3
### 3. break and continue
--`break-continue.sh`--
```bash
#!/usr/bin/env bash
# use '@' for entering more than one inputs (simply an array)
# Pass the values from command line arguments
names=$@
# use of break
for name in $names
do
if [ $name = "Andy" ]
then
echo "End found"
break
else
echo "Hello, $name"
fi
done
echo "for loop terminated"
# use of continue
for name in $names
do
if [ $name = "Andy" ]
then
echo "Skip found"
continue
else
echo "Hello, $name"
fi
done
echo "for loop terminated"
exit 0
```
`$ break-continue.sh "Vikas" "Andy" "Mark"`
> Hello, Vikas
> End Found
> for \ loop terminated
> Hello, Vikas
> Skip found
> Hello, Mark
> for \ loop terminated
## Working with environment variables
We can access any of the environment variable from the bash script.
--`vars.sh`--
```bash
#!/usr/bin/env bash
# environment variables
echo "The path is : $PATH"
echo "The terminal is : $TERM"
echo "The editor is : $EDITOR"
# -z checks for empty
if [ -z $EDITOR ]
then
echo "The Editor variable is empty"
fi
exit 0
```
`$ ./vars.sh`
> The path is : \
> The terminal is : xterm-256color
> The editor is :
> The Editor variable is empty
##### Environment variables and their meaning
HOME : user's home directory
PATH : executable binary's path
HOSTNAME : hostname of the machine
SHELL : shell that is being used
USER : user of this session
TERM : type of command line terminal that is being used
##### write a program to print user's name, computer name, and home directory
```bash
echo "$USER@$HOSTNAME in [$HOME]"
```
> vikas@DAVE in [/home/vikas]
## Functions in bash
There are two ways to create functions in _bash_ :
#### 1. Function declaration syntax with _function_ keyword
-`function1.sh`-
```bash
#!/usr/bin/env bash
function greeting(){
echo "Hello"
}
```
#### 2. Function declaration without keyword
-`function2.sh`-
```bash
#!/usr/bin/env bash
greeting(){
echo "Hello"
}
```
#### 3. Calling the function
To call the function we just need to use the name of the function, we do not use parentheses as we use in other programming languages (e.g. C, C++, Java, Python, etc.).
-`function1.sh`-
```bash
#!/usr/bin/env bash
# declare the function
function greeting(){
echo "Hello"
}
# calling the function
greeting
```
**`$ bash ./function1.sh`**
> Hello
#### 4. What about passing parameters ?
It's a two step process
1. **Access the parameter value**
To access the parameter use :
_`$1`_: for first parameter,
_`$2`_: for second parameter,
... ,
_`$n`_: for nth parameter.
You can either create a local variable and save the value by _`local variable=$n`_ or directly access the value by _`$n`_ (n is the parameter number 1, 2, 3, etc).
2. **Pass the parameter value**
To pass the value write the value after the function name while calling the function (seperate by space).
`add 2 3`
#### 5. Complete example
-`function.sh`-
```bash
#!/usr/bin/env bash
function add(){
local num1=$1
local num2=$2
sum=`expr $num1 + $num2`
echo "Sum=$sum"
}
# call the function
add 2 3 # 5
add 4 5 # 9
add -10 30 # 20
# or use command line arguments (uncomment if used)
# add $1 $2
```
**`$ bash ./function.sh`**
> 5
> 9
> 20
## Working with prompt message
You can write a message when asking the user for input.
It can be done by using **`read`** command.
-`user-prompt.sh`-
```bash
#!/usr/bin/env bash
read "Hey, What's your name ?" name
echo "Hello, $name"
```
**`$ bash ./user-prompt.sh`**
> Hey, What's your name ?
> Vikash
> Hello, Vikash
If you want the input to be in the same line use **`-p`**..
-`user-prompt2.sh`-
```bash
#!/usr/bin/env bash
read -p "Hey, What's your name ?" name
echo "Hello, $name"
```
**`$ bash ./user-prompt2.sh`**
> Hey, What's your name ? Vikash
> Hello, Vikash
---
_Now you have enough understanding to get started with bash (shell) scripting. Go ahead an read a book or two on bash scripting and you will be good at it._
**_Keep Learining, Keep Practicing. :) :)_**
---
That's All. 😅
Thanks for reading. 🙏
If you liked it feel free to share with your dear ones.💗
And tell me what do you think in the comment box.💬
Stay tuned with CS111.
This post was originally posted on [Village Programmer](https://villageprogrammer.blogspot.com)
---
## Access Wsl Filesystem From Windows 10 File Explorer
**Date:** 2021-05-04
**URL:** https://lorbic.com/access-wsl-filesystem-from-windows-10-file-explorer/
**Description:**

If you want to get Linux environment in your Windows system there are some solutions that provide the opportunity.\
For example MYSYS, CYGWIN and a Virtual Machine (If you want complete linux machine) or Multiple Boot.\
But some of them aren't much powerful and some are resources hungry like Virtual Machine.\
So, the solution is **WSL (Windows Subsystem for Linux)**.\
You can learn how to setup WSL from [here](https://docs.microsoft.com/en-us/windows/wsl/install-win10#manual-installation-steps).
In this article I'll be sharing how to access WSL file system from Windows 10 file explorer.\
I am assuming you have completely setup WSL and is able to access it through command prompt/powershell.
### Step 1
Open Windows Explorer\
Then type `\\wsl$` in the path location as shown in the below picture and hut enter. 
### Step 2
Now a new window will open having your WSL linux machine name.
### Step 3
Now right click on the icon shown in the above image (Name may not be the same)
### Step 4
Now Select `Map Network Drive` option.\
A new diaglog box will open, As shown in the below picture.
Now choose a drive letter and click **Finish**.
### Step 5
You will have the Linux machine file system listed under Network Storage.
### Conclusion
You can view, rename, delete, copy/paste the files as you do with normal windows files.\
But do not delete any of the files you don't know. If you do that it may break the WSL System.
That's all from my side.
Thanks for reading. 🙏\
If you liked it feel free to share with your dear ones.💗\
And tell me what do you think in the comment box.💬
Stay tuned with CS111.
This post was originally posted on [Village Programmer](https://villageprogrammer.blogspot.com)