dgplug member blogs

Reader

Read the latest posts from dgplug member blogs.

from jason’s dgplug blog

Notes while I fiddle with the servers

The Big Idea

  • Move from Debian to Flatcar on the main server.
  • I wanted to move to something completely black box and appliance like Talos, but I am not that brave. I still want my K3s, and my instance is not that large that I can run full fat Kubernetes.

2026-10-22 09:45

  • Good I decided to review my files. If I had just generated a new instance on Hetzner, I might have paid double for the instance I use (CPX32)
  • Moved my terraform state from s3 to local.
  • S3 meant my self hosted Garage instance. Found that I did not use it as much as I intended. So will retire it. (That will probably be phase two when I revamp the home network). Since last December I’ve hardly touched the state of the VM. So makes sense for me to maintain state locally.
  • Found that OpenTofu can encrypt at rest local tf state files. Time to move from Terraform to OpenTofu
  • 2026-10-22 10:45: Buggered it up enough, between backups and moving VMs that the current thing will destroy my VM. that is what I don’t want! will need to see what to do. But the dream of just changing enough stuff is gone now.
  • my dream of an entirely gitops driven workflow is undone by the ai-pocalypse
  • options? am too used to this machine to downgrade. so will manually nurse it.
  • worst case option? will downgrade if it comes to that.

2026-10-22 11:05

  • Just realised that the PHP world is on fire.
  • Taking a break from doing things above to adapting two images for my containers
 
Read more...

from Titas Dey

I don't know if it's worth it to know how to count in binary. Irrespective of it I'll share some observations I made a year back.

How Numbers are Written ....

Radix(orBase) : The number of unique symbols or digits in a system. If a system has a radix R, the allowable digits are 0 through R-1. i.e. radix 5 means, digits from 0 to 4 .

Counting is done recursively , here for radix 5 the numbers will be written as: 0,1,2,3,4,10,11,12,13,14,20,21,22,23,24,30... so on

0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15.... This is for decimal numbers

We can observe (10) in base 5 == (5) in base 10

The maximum unique digits in base 5 is five, so counting from 0-4 we exhaust all our options , to write the next number we need another digit. Hence we bring a 1 ahead and reset the numbers right of it. The numbers after 4 becomes 10,11,12,13,14 again we exhaust all the options with 1 fixed , so we make it 2 and reset the numbers in right of it to 0, now we'll have five more numbers 20,21,22,23,24 this goes on till 44. Here we've exhausted all numbers that can be created with 2 spaces so we'll need another space and the next number will be (100)base5.

The main observation is : For Radix (N) the maximum unique numbers by r digits == N^r eg. Maximum unique numbers in decimal number system by 2 digits ==> 10^2 = 100 0 to 99 For Radix (N) a number written in the format (N-1) (N-1) (N-1) (N-1) ...for r terms = N^r – 1 (N-1) 00000.... upto r zeros = N^r

eg. (444) base 5 = (5^3-1) i.e 124 in decimal eg. (1000) base 9 = 9^3 = 729

Counting in Binary

Now that we're clear with the basics

1> consecutive 1's written r times = 2^r-1 eg. (1111)2 => 2^4-1 = 15

2> 1 followed by r zeros = 2^r eg. (100000)2 => 2^5 = 32

3> Sticking 1 zero after a number means multiplying with 2 eg. (10)2 = 2 then (100)2 = 2*2 = 4

4> Sticking one 1 after a number means multiplying with 2 + 1 eg. (111)2 = 7 then (1111)2 = 7 X 2 +1 = 15

5> Memorise the first 4 binary numbers – (0)2 = 0 – (1)2 = 1 – (10)2 = 2 – (11)2 = 3

Some Examples:

eg.1) Say we have (11001)2, > we know 11 = 3 then the number = ((3 x 2) x 2)x2+1 = 25

eg.2) (11110110)2 > we know 1111 = 15 (i.e 2^4-1) , the number will be ((((15x2)x2+1)x2+1)x2) = 246

eg.3) Convert 211 to binary > we can think 211 = 255-44 > The 255 = 2^8-1 , so 8 consecutive 1s, and we remove 44 i.e(32+8+4) from it , > (11111111)2 is 255, now we remove the 1s from 2^5 , 2^3, 2^2 s places and leave them with 0s > (11010011)2 is 211

Thats it

Thats pretty much it. These are just patterns , once you see them you can't unsee them. Whether it's actually useful , I still don't know.

 
Read more...

from Titas Dey

Been learning about asymptotic analysis.

Definition: Asymptotic analysis is the study of the growth of an algorithm’s running time or space requirement as a function of the input size n, for large values of n, while ignoring constant factors and lower-order terms.

In other words, we analyze how the resource consumption of an algorithm scales as the problem size becomes large.

Time Complexity != Time taken by the algorithm to run

Time complexity is a function f(n) that represents the number of elementary operations performed by an algorithm as a function of input size n ∈ ℕ.

T(n) = number of primitive steps executed for input size n

  • Asymptotic analysis is independent of

    • Hardware specifications
    • Programming language
    • Operating system and runtime environment
    • Input distribution (for a fixed n)

Big-Oh Notation (O-notation)

Definition: Let f(n) and g(n) be functions mapping positive integers to positive real numbers. We say that g(n) is O(f(n)) (read “g of n is big-oh of f of n”) if there exist positive constants c ∈ ℝ⁺ and n₀ ∈ ℕ such that:

g(n) ≤ c·f(n) ∀ n ≥ n₀

The function f(n) is called an asymptotic upper bound for g(n). Intuitively, this means that g(n) grows no faster than f(n), up to a constant multiplicative factor, for sufficiently large values of n.

Visually , if we plot both g(n) and f(n) and can find some point n₀ in the input axis beyond which c·f(n) always stays above g(n). Then g(n) is O(f(n)). i.e We use Big-Oh if we are concerned with the worst case performance of the algorithm

eg:

Say f(n) = 3n² + 5n + 10 , g(n) = n². g(n) = O(f(n)) & f(n) = O(g(n))

If we analyse this

We need to find constants c ∈ ℝ⁺ and n₀ ∈ ℕ such that:

f(n) ≤ c·g(n) ∀ n ≥ n₀

Substituting: 3n² + 5n + 10 ≤ c·n²

For n ≥ 1: – 5n ≤ 5n² – 10 ≤ 10n²

Therefore: 3n² + 5n + 10 ≤ 3n² + 5n² + 10n² = 18n²

Conclusion: Choose c = 18 and n₀ = 1. Then f(n) ≤ 18·g(n) ∀ n ≥ 1.

Hence, f(n) = O(g(n)) or more specifically, f(n) = O(n²).

Again (n) ≤ c·f(n) ∀ n ≥ n₀

Substituting: n² ≤ c(3n² + 5n + 10)

Since f(n) = 3n² + 5n + 10 > 3n² for all n ≥ 1, we have:

n² ≤ 3n² + 5n + 10

This is clearly true for all n ≥ 1.

Conclusion: Choose c = 1 and n₀ = 1. Then g(n) ≤ 1·f(n) ∀ n ≥ 1.

Hence, g(n) = O(f(n)).

Big-Oh Represents a Set of Functions

Say , some T(n) = n³ then
3n² + 5n + 10 = O(T(n))..................i
5n+7 = O(T(n)).........................ii
log(n) = O(T(n))_____iii

if we analytically approach eq(i),eq(ii),eq(iii). All 3 are True But eq(i) != eq(ii) != eq(iii)

When we write f(n) = O(g(n)), the ”=” is not a true equality.

More Precisely: O(g(n)) represents an infinite set of all functions that grow no faster than g(n). So f(n) = O(g(n)) really means f(n) ∈ O(g(n))

Example: O(n²) is the set containing functions like: – n² – 3n² + 5n + 10 – n² + 100n – 50n + 1000 – 5 (constant) – log n

All these functions belong to the set O(n²) because they all grow no faster than n².

When we write O(n²), we're saying that as the input size n becomes very large, the running time grows at most proportionally to n². The constant factors and lower-order terms become negligible in comparison to the dominant term, which is why we drop them in Big-Oh notation. For instance, an algorithm that takes 3n² + 5n + 10 operations is simply O(n²) because the n² term dominates as n approaches infinity.

i.e: We simply ignore the lower order and constant terms when were trying to find the time complexity in Big-Oh


Some Commonly Seen Cases

O(1) – Constant Time: These operations take the same amount of time regardless of input size. Accessing an array element by index, performing arithmetic operations, and returning a value are all O(1) operations. No matter if our array has 10 elements or 10 million elements, accessing the element at index 5 takes the same time.

O(log n) – Logarithmic Time: Algorithms that repeatedly divide the problem space in half exhibit logarithmic complexity. Binary search is the classic example, where we eliminate half of the remaining elements with each comparison. As n doubles, the running time increases by only a constant amount.

O(n) – Linear Time: When we must examine every element exactly once, we have linear complexity. A simple loop that processes each element in an array demonstrates O(n) behavior. If we double the input size, the running time doubles as well.

O(n log n) – Linearithmic Time: Efficient sorting algorithms like merge sort and heap sort operate in O(n log n) time. This complexity arises when we perform a logarithmic number of linear operations or divide-and-conquer with linear merging.

O(n²) – Quadratic Time: Nested loops where each loop runs n times typically result in quadratic complexity. Simple sorting algorithms like bubble sort and selection sort fall into this category. Doubling the input size quadruples the running time.

O(n³) – Cubic Time: Triple-nested loops often produce cubic complexity. Matrix multiplication using the naive algorithm is a prime example.

O(2ⁿ) – Exponential Time: The recursive Fibonacci function is a classic example, where each call branches into two more calls. The running time doubles with each increment of n, making it impractical for even moderately sized inputs.

O(n!) – Factorial Time: Generating all permutations of n elements produces factorial complexity. For n = 10, that's 3,628,800 operations. Yes calculated that in my head,absolutely did not google.

O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(n³) < O(2ⁿ) < O(n!)


Analyzing Some Algorithms

Example 1: Array Sum

def array_sum(arr):
    total = 0
    for element in arr:
        total += element
    return total

The loop runs once per element. Each iteration does constant work. Time complexity: O(n).


Example 2: Finding Maximum Element

def find_max(arr):
    if len(arr) == 0:
        return None
    max_val = arr[0]
    for i in range(1, len(arr)):
        if arr[i] > max_val:
            max_val = arr[i]
    return max_val

Single pass through the array with constant-time operations per iteration. Time complexity: O(n).


Example 3: Bubble Sort

def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]

Nested loops result in roughly n² comparisons. Time complexity: O(n²).


Analyzing a Slightly More Complex Program

def binary_search(arr, target):
    left = 0
    right = len(arr) - 1
    
    while left <= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return -1

Initially, the search space has size n. After each iteration: – 1st iteration: n elements – 2nd iteration: n/2 elements – 3rd iteration: n/4 elements – kth iteration: n/2^(k-1) elements

The loop continues until the search space is reduced to 1 element or becomes empty. We need to find k such that:

n/2^(k-1) ≤ 1

Solving for k: – n ≤ 2^(k-1)

  • log₂(n) ≤ k – 1

  • k ≥ log₂(n) + 1

Therefore, the loop executes at most ⌈log₂(n)⌉ + 1 times (ceiling of log₂(n) plus 1).

Since each iteration performs O(1) operations (comparisons, assignments, arithmetic), the total time complexity is : T(n) = O(1) + O(log n)·O(1) + O(1) = O(log n) .

i.e T(n) = O(log(n)) for Binary Search

Conclusion:

  • Big-Oh gives an upper bound on how an algorithm scales as input size increases
  • We analyse for n → ∞
  • Constant terms and lower order terms are ignored
print("Titas,Signing Out!")

 
Read more...

from sandeepk

A few days ago, during our office knowledge-sharing meeting, someone introduced the git worktree command. It lets you create a new branch parallel to your current working branch so you can start something new — or handle a hotfix — without stashing or committing your unfinished changes.

It turned out to be incredibly useful. With git worktree, you can maintain multiple working directories linked to the same Git repository with almost no friction.


Why use worktrees?

Imagine you're working on a long-running feature — say, an optimization — and suddenly you’re assigned an urgent production bug. Typically, you would stash your changes or make a temporary commit, switch branches, fix the bug, then restore everything. It's annoying and error-prone.

With worktrees, you can directly spin up a parallel working directory:

git worktree add <path>
# Example:
git worktree add ../hotfix

This creates a new linked worktree, associated with your current repository, with its own metadata and branch checkout. Your original work remains untouched.


Removing a worktree

Once you're done with the hotfix (or any task), removing the worktree is just as simple:

git worktree remove <path>

If you delete the directory manually, Git will eventually clean up its administrative files automatically (based on gc.worktreePruneExpire in git-config). You can also remove stale entries explicitly:

git worktree prune

Other useful worktree commands

1. Create a throwaway worktree (detached HEAD)

Perfect for quick experiments:

git worktree add -d <path>

2. Create a worktree for an existing branch

git worktree add <path> <branch>

This checks out the given branch into a new, isolated working directory.


Further reading

To dive deeper into git worktree:

  git help worktree

Cheers!

#Git #TIL #Worktree

 
Read more...

from Titas Dey

Well the title is a clickbait,but it’s true in a limited sense.

If you've written some C code you've probably used most of the features in C like structure,functions,pointers,arrays and perhaps even the preprocessor.

However, I will talk about one of the lesser used features in C – union


The Union

A union allocates a single shared block of memory, large enough to hold its largest member (with some padding, depending on alignment). Unlike a struct, which allocates distinct memory for each member, a union allows multiple members to occupy the same memory space.

For example:

#include<stdio.h>
#include<string.h>

struct xyz {
    int x;
    float y;
    char z[10];
};

union tuv {
    int t;
    float u;
    char v[10];
};

int main(void) {
    struct xyz st_eg;
    union tuv un_eg;

    printf("%d\n", sizeof(st_eg)); // O/P: 20 bytes (4 + 4 + 10 + 2 bytes padding)
    printf("%d\n", sizeof(un_eg)); // O/P: 12 bytes (10 bytes for v + 2 bytes padding)

    strcpy(&un_eg.v, "HelloWorld");

    printf("%s\n", un_eg.v);  // O/P: HelloWorld 
    printf("%f\n", un_eg.u);  // O/P: 1143139122437582505939828736.000000

    return 0;
}

Here, both the integer, float, and character array occupy the same memory region. When "HelloWorld" is copied into the character array v, reading that memory as a float outputs the string "HelloWorld" typecasted into float a short essay on union.


  • But why do we need union ?
  • Why to allocate memory for only the largest member and not all of them using struct ?

A union is valuable when you want different interpretations of the same memory.


Example 1: Storing an IPv4 Address

#include<stdio.h>

typedef union {
    unsigned int ip_add;
    unsigned char bytes[4];
} ipv4_add;

int main(void) {
    ipv4_add my_address = {0};

    my_address.bytes[0] = 127;
    my_address.bytes[1] = 55;
    my_address.bytes[2] = 115;
    my_address.bytes[3] = 0;

    printf("%x\n", my_address.ip_add); // O/P: 73377f
    return 0;
}

Explanation

Using a union, we can store both the integer representation and the byte-wise representation of an IPv4 address within the same space. This approach eliminates the need for explicit bit-shifting or manual conversions.


Example 2: Unions in Embedded Programming

Unions are widely used in embedded systems to represent hardware registers that can be accessed both as a whole and as individual fields.

#include<stdio.h>

union HWRegister {
    struct { // annonymous structure
        unsigned char parity;
        unsigned char control;
        unsigned char stopbits;
        unsigned char direction;
    };
    unsigned int reg;
};

int main(void) {
    union HWRegister gpioa;

    gpioa.reg = 0x14424423;
    printf("%x\n", gpioa.stopbits); // O/P: 14

    return 0;
}

In this example, the same memory can be accessed as a single 32-bit register or through specific bit fields. This design improves clarity while maintaining memory efficiency — a common requirement in low-level programming.


Example 3: A Glimpse of Polymorphism in C

Now coming back to the title , we can do something similar to OOP in C:

#include<stdio.h>

typedef enum {
    JSON_STR,
    JSON_BYTE,
    JSON_INT,
} json_type_t;

#define JSON_MAX_STR 64

typedef struct {
   json_type_t type;
   union {
       char str[JSON_MAX_STR];
       char byte;
       int number;
   };
} json_t;

void printJSON(json_t *json) {
    switch (json->type) {
        case JSON_STR:
            printf("%s\n", json->str);
            break;
        case JSON_BYTE:
            printf("%c\n", json->byte);
            break;
        case JSON_INT:
            printf("%d\n", json->number);
            break;
    }
}

int main(void) {
    json_t myJSON;
    myJSON.type = JSON_INT;
    myJSON.number = 97;

    printJSON(&myJSON);
    return 0;
}

Here, the structure json_t can hold one of several possible data types — a string, a single byte, or an integer. The active type is determined at runtime using the type field.

There are some issues in this , in C the types are not tightly enforced by the compiler , so if we do

myJSON.type = JSON_STR;// // instead of JSON_INT
myJSON.number = 97;
printJSON(&myJSON); // O/P: a 
  • The output will be : a (the ascii charector of value 97)

And that's all.

print("Titas , signing out ")
 
Read more...

from Titas Dey

Arrow Function vs Regular Function in JavaScript

Yeah, everyone already knows the syntax is different. No need to waste time on that.

Let’s look at what actually matters — how they behave differently.


1. arguments

Regular functions come with this built-in thing called arguments object. Even if you don’t define any parameters, you can still access whatever got passed when the function was called.

Arrow functions? Nope. No arguments object. Try using it, and it’ll just throw an error.

Regular function:

function test() {
  console.log(arguments);
}

test(1, "hello world", true); 
// o/p
// { '0': 1, '1': 'hello world', '2': true }

Arrow function:

const test = () => {
  console.log(arguments); 
};

test(1, "hello world", true); // Throws ReferenceError

2. return

Arrow functions have implicit return but regular functions don't. i.e We can return the result automatically if we write it in a single line , inside a parenthesis in arrow functions. Regular functions always require the return keyword.

Regular function:

function add(a, b) {
 const c = a + b;
}

console.log(add(5, 10)); // o/p : undefined 

Arrow function:

const add = (a, b) => (a + b);

console.log(add(5, 10)); // o/p : 15

3. this

Arrow functions do not have their own this binding. Instead, they lexically inherit this from the surrounding (parent) scope at the time of definition. This means the value of this inside an arrow function is fixed and cannot be changed using .call(), .apply(), or .bind().

Regular functions, on the other hand, have dynamic this binding — it depends on how the function is invoked. When called as a method, this refers to the object; when called standalone, this can be undefined (in strict mode) or refer to the global object (in non-strict mode).

Because of this behavior, arrow functions are commonly used in cases where you want to preserve the outer this context, such as in callbacks or within class methods that rely on this from the class instance.

Regular function :

const obj = {
  name: "Titas",
  sayHi: function () {
    console.log(this.name);
  }
};

obj.sayHi(); // o/p : Titas

Arrow function :

const obj = {
  name: "Titas",
  sayHi: () => {
    console.log(this.name);
  }
};

obj.sayHi(); // o/p :  undefined

print("Titas signing out !")
 
Read more...

from sandeepk

So I was fixing some slow tests, and whenever I ran them through the pytest command, I was greeted with the dreaded max_locks_per_transaction error.

My first instinct? Just crank up the max_locks_per_transaction from 64 to 1024.

But... that didn’t feel right. I recreate my DB frequently, which means I’d have to set that value again and again. It felt like a hacky workaround rather than a proper solution.

Then, like any developer, I started digging around — first checking the Confluence page for dev docs to see if anyone else had faced this issue. No luck. Then I moved to Slack, and that’s where I found this command someone had shared:

pytest -n=0

This was new to me. So, like any sane dev in 2025, I asked ChatGPT what this was about. That’s how I came across pytest-xdist.

What is pytest-xdist?

The pytest-xdist plugin extends pytest with new test execution modes — the most common one is distributing tests across multiple CPUs to speed up test execution.

What does pytest-xdist do?

Runs tests in parallel using <numprocesses> workers (Python processes), which is a game changer when: – You have a large test suite
– Each test takes a significant amount of time
– Your tests are independent (i.e., no shared global state)


That’s pretty much it — I plugged in pytest -n=0 and boom, no more transaction locks errors.

Cheers!

References – https://pytest-xdist.readthedocs.io/en/stable/ – https://docs.pytest.org/en/stable/reference/reference.html

#pytest #Python #chatgpt #debugging

 
Read more...

from Titas Dey

The college is really gonna teach us Data Structures and Algorithms in C . And make me write 100 line codes in paper for lab manuals .

 
Read more...

from sandeepk

I’ve been working on a few side projects and using ChatGPT for ideation and brainstorming around ideas and features for the MVP. As part of this, I needed a logo for my app. Naturally, I turned to AI to help me generate one.

However, I noticed that when generating images, ChatGPT doesn’t always follow the guidelines perfectly. Each time I asked for a new version, it would create a completely different image, which made it difficult to iterate or make small tweaks.

But I found a better way.

Instead of generating a brand new image every time, I first explained my app idea and the name. ChatGPT generated an image I liked.

So I asked ChatGPT to generate the JSON for the image instead. I then manually tweaked the JSON file to adjust things exactly the way I wanted. When I asked ChatGPT to generate the image based on the updated JSON, it finally created the image as per my request — no random changes, just the specific adjustments I needed.

Exploration Phase

SplitX logo

{
  "image": {
    "file_name": "splitX_icon_with_text.png",
    "background_color": "black",
    "elements": [
      {
        "type": "text",
        "content": "SplitX",
        "font_style": "bold",
        "font_color": "white",
        "position": "center",
        "font_size": "large"
      },
      {
        "type": "shape",
        "shape_type": "X",
        "style": "geometric split",
        "colors": [
          {
            "section": "top-left",
            "gradient": ["#FF4E50", "#F9D423"]
          },
          {
            "section": "bottom-left",
            "gradient": ["#F9D423", "#FC913A"]
          },
          {
            "section": "top-right",
            "gradient": ["#24C6DC", "#514A9D"]
          },
          {
            "section": "bottom-right",
            "gradient": ["#514A9D", "#E55D87"]
          }
        ],
        "position": "center behind text",
        "style_notes": "Each quadrant of the X has a distinct gradient, giving a modern and vibrant look. The X is split visually in the middle, aligning with the 'Split' theme."
      }
    ]
  }
}

Final Design

SplitX logo Updated JSON

{
  "image": {
    "file_name": "splitX_icon_with_text.png",
    "background_color": "transparent",
    "elements": [
      {
        "type": "shape",
        "shape_type": "X",
        "style": "geometric split",
        "colors": [
          {
            "section": "top-left",
            "gradient": [
              "#FF4E50",
              "#F9D423"
            ]
          },
          {
            "section": "bottom-left",
            "gradient": [
              "#F9D423",
              "#FC913A"
            ]
          },
          {
            "section": "top-right",
            "gradient": [
              "#24C6DC",
              "#514A9D"
            ]
          },
          {
            "section": "bottom-right",
            "gradient": [
              "#514A9D",
              "#E55D87"
            ]
          }
        ],
        "position": "center ",
        "style_notes": "Each quadrant of the X has a distinct gradient, giving a modern and vibrant look. The X is split visually in the middle, aligning with the 'Split' theme."
      }
    ]
  }
}

If you want to tweak or refine an image, first generate the JSON, make your changes there, and then ask ChatGPT to generate the image using your updated JSON. This gives you much more control over the final result.

Cheers!

P.S. Feel free to check out the app — it's live now at https://splitx.org/. Would love to hear what you think!

 
Read more...

from sandeepk

1. Why did you make the blog in the first place?

This blog initially started as part of the summer training by DGPLUG, where the good folks emphasize the importance of blogging and encourage everyone to write—about anything! That motivation got me into the habit, and I’ve been blogging on and off ever since.

2. What platform are you using to manage your blog and why did you choose it?

I primarily write on WriteFreely, hosted by Kushal, who was kind enough to host an instance. I also occasionally write on my WordPress blog. So yeah, I have two blogs.

3. Have you blogged on other platforms before?

I started with WordPress because it was a simple and fast way to get started. Even now, I sometimes post there, but most of my recent posts have moved to the WriteFreely instance.

4. How do you write your posts?

I usually just sit down and write everything in one go. Followed by editing part—skimming through it once, making quick changes, and then hitting publish.

5. When do you feel most inspired to write?

Honestly, I don’t wait for inspiration. I write whenever I feel like it—sometimes in a diary, sometimes on my laptop. A few of those thoughts end up as blog posts, while the rest get lost in random notes and files.

6. Do you publish immediately after writing or do you let it simmer a bit as a draft?

It depends. After reading a few books and articles on writing, I started following a simple process: finish a draft in one sitting, come back to it later for editing, and then publish.

7. Your favorite post on your blog?

Ahh! This blog post on Google Cloud IAM is one I really like because people told me it was well-written! :)

8. Any future plans for your blog? Maybe a redesign, changing the tag system, etc.?

Nope! I like it as it is. Keeping it simple for now.

A big thanks to Jason for mentioning me in the challenge!

Cheers!

 
Read more...

from mrinalraj

Hey there! 👋 Welcome to my personal insights from the incredible Aero India 2025 event held at Yelahanka Air Base, Bengaluru! 🇮🇳✨ Buckle up, and let’s dive into this high-flying adventure! 🛩️🔥


🌅 Early Bird Adventures

Woke up super early ⏰ to beat the traffic towards Yelahanka ✨
Quickly grabbed some breakfast 🥪☕ and rushed to the bus stop 🚌
Took a connection via Hebbal ➡️ and then headed straight to Yelahanka Air Base 🚏🛫


👫 New Friends & Quick Access

Met some amazing people on the way 👋 — especially Shelja from HAL 👩‍🔧 who helped me get into the ADVA area swiftly 🔐💨
Such warmth and camaraderie! ❤️


🪑 Perfect Spot for Viewing

There were special seating arrangements 🎟️ with a direct view of the majestic birds in the sky 🛫🦅
There was a major buzz around:

  • 🇷🇺 Su-57
  • 🇺🇸 F-35
  • 🇮🇳 Hansa-S performing jaw-dropping aerobatics 🔄🎯

The sky was on 🔥 with excitement!


📅 How You Can Experience It Too!

🗓️ Dates: 10th – 14th Feb 2025
🎫 Single-Day Entry Passes Only

💼 Business Pass

  • Access to: Exhibitions (IDEX), Seminars, and Air Show (ADVA)
  • ❌ Excludes invite-only events (like Raksha Mantri Dinner, CEO Meet)
  • 💸 Cost: ₹5000/day

🎟️ ADVA Pass

  • Access to: Air Show and select exhibitions
  • ❌ May not include halls with foreign exhibitors (🇮🇱 Israel, 🇫🇷 Safran, 🇬🇧 Rolls-Royce, etc.)
  • 💸 Cost: ₹1000/day

🧑‍🤝‍🧑 General Pass

  • Access to: ADVA + Exhibitions
  • Only valid on: 4th & 5th day of the event
  • 🚸 Expect it to be crowded
  • 💸 Cost: ₹2500/day

🎫 My Experience with the Business Pass

Got myself a Business Pass 😎
Went straight to ADVA after a thorough bag check 🧳🔍
💡 Pro Tip: You can carry your own water bottle & snacks (chips, etc.) 💦🍿

By 11:45 AM, the air show was done 💥
I dashed over to the Exhibition Hall 🏛️ where I saw:

  • The mighty 🇮🇳 Kaveri Engine
  • Cutting-edge defense tech usually not open to public 👀📸

And yes, photography was allowed! 📷✨


🎤 Tech Talks & Seminars

After a bit of a hunt 🧭 I found the Seminar Hall
Was warmly welcomed 🤝 and walked into a room filled with:

  • 🪖 Top military generals
  • 💼 Business leaders from GE, Rolls-Royce, Safran

It was just wow — an incredible energy of innovation and strategy in the room! 🌐⚙️


🏁 Conclusion

This was a once-in-a-lifetime event 💫
I met brilliant minds 🧠, saw next-gen tech 🔧, and watched thrilling air stunts in real-time 🛩️💨

Highly recommend not missing this epic celebration of India's aviation might 🇮🇳✈️


💬 Got questions or want to connect?
📧 Reach me at: reach.mrinalraj@gmail.com
Let the skies inspire you! 🌤️🇮🇳

 
Read more...

from mrinalraj

Scenario

Folks! Have you ever wondered how to create a URL that always points to your router, even when its public IP address changes? It might sound complex and costly, but it's actually free!

Concept

This involves setting up Dynamic DNS (DDNS).

What you need

  1. A Wi-Fi Router supporting NO-IP as DDNS
  2. An account on NO-IP website

Steps for creating hostname in NO IP:

  1. Login to NO-IP website. Make sure to avoid use of special character in the password.
  2. Create a hostname.
  3. We are Done!!!

Steps for configuring DDNS in router:

  1. Login to your router with credentials.
  2. Navigate to DDNS which would possibly under Internet tab.
  3. Configuring DDNS. 3.1 Keep WAN Connection as 'auto'. 3.2 Provider: 'No-IP' 3.3 Username: 3.4 Password: 3.5 Hostname: Give the newly created hostname
  4. We are Done!!!

Testing

Reboot your router and verify if NO IP website is showing the recent router's public IP.

Result

Now every time your router public IP changes it would reflect the recent IP on the website.

Usage

NO-IP provides a free DDNS hostname that can be used in projects instead of the router's public IP address. Simply confirm the renewal email after 30 days.

Thank you !!! Follow Mrinal

 
Read more...

from mrinalraj

Scenario

Imagine wanting to stream video from a device behind your home router to your personal phone over the internet. This may sound like a complex task, but with port forwarding, it's simpler than you think.

What you need:

  1. A Wi-Fi Router
  2. A computer displaying the video feed connected to the Wi-Fi router
  3. A VNC viewer on your remote mobile device

The Solution:

Port forwarding is the secret sauce that makes this setup seamless. Here's how you can do it:

Steps:

Router –> Computer –> Display | Internet –> Mobile –> VNC

  1. Lets Visualize the network diagram as above.
  2. Be physically near your router.
  3. Login your Wi-Fi router with credentials.
  4. Navigate to Port Forwarding section. It must be in the Security section.
  5. Set the Port forwarding rules 5.1. Service Name: Give the port forwarding rule a descriptive name. 5.2. Port Range: Specify the range of ports you want to forward (e.g., 5900- 5901 for a single port). 5.3. Local IP Address: Enter the IP address of the device on your local network that you want to forward the ports to. Refer my previous post on How to make a connected device static. 5.4. Protocol: Select the protocol for the port forwarding rule (TCP, UDP, or both). 5.5 Keep WAN HOST IP as 0.0.0.0

We are done here!!! See its that simple. Lets now test it over is my port open? website.

On Personal Mobile over Internet

  1. Install VNC over mobile phone
  2. Enter the router public IP followed by port number eg. 24.57.121.123:5900
  3. Suppose you don't have a router public IP address handy you can get it from what's my IP address? website.
  4. Above IP means that in the router public IP, connect to device at port 5900
  5. Enter credentials and we are done!!!

Limitation

  1. Since your router IP changes after reboot. Refer my previous post on How to get free url for Router's public IPs
  2. If the local device streaming feed is not static. It me loose the IP after device restart. Making device static is better solution. Refer my previous post on How to make a connected device static.

Thank you !!! Follow Mrinal

 
Read more...

from mrinalraj

Scenario

I recently needed to establish a static IP for my Python project to facilitate SSH access. The issue I faced was that DHCP kept assigning a new IP every time my system rebooted.

I discovered that we can set the IP address to be static, and the steps for doing so are outlined below:

About:

dhcpcd.conf:

Location: /etc/dhcpcd.conf Usage: DHCP client daemon is used towards the client side to configure the interfaces.

while

dhcpd.conf

Location: /etc/dhcp/dhcpd.conf Usage: It acts as server for dynamically assigning IPs to devices in the network

Step 0: Setup dhcpcd:

Install: sudo apt-get install dhcpcd Enable: sudo systemctl enable dhcpcd sudo systemctl start dhcpcd Verify: sudo systemctl status dhcpcd

Step 1: Open the dhcpcd.conf file

sudo nano /etc/dhcpcd.conf

If your project uses Wi-Fi, proceed with the following steps; otherwise, replace the interface name accordingly. interface wlan0 static ip_address=your_desired_static_ip/24 static routers=your_router_ip static domain_name_servers=your_dns_server_ip or interface wlan0 static ip_address=your_desired_static_ip/24 static routers=192.168.0.1 static domain_name_servers=192.168.0.1 8.8.8.8

Replace “your_desired_static_ip”, “your_router_ip”, and “your_dns_server_ip” with the appropriate values for your network. Ensure you choose an IP address that is not already in use on your network.

How to get router ip: Refer whats my ip address?

How to get the dns server: On terminal do nslookup google.com

Note: you need to have package 'dnsutils' installed. (sudo apt-get install dnsutils)

Step 2: Restart the dhcp service

sudo service dhcpcd restart or do sudo reboot

 
Read more...

from mrinalraj

Scenario

I recently wanted my Python program to execute right after the system boots up. I discovered several options to achieve this, eliminating the need for manual intervention to run the program.

Option 1: Editing through Crontab

  1. Open a terminal with elevated privileges: sudo su -
  2. Edit the crontab configuration: crontab -e
  3. Add the following command to start the Python program (assuming you want to run it on a Raspberry Pi terminal): ```bash
  4. @reboot /usr/bin/python3 /path/to/your/script.py

Option 2: Editing through services using systemd

  • Create a script, name it as “myscript.sh”
  • Make the script executable: chmod +x myscript.sh
  • Navigate to the systemd directory: cd /etc/systemd/system/
  • Create a service file named “myscript.service” inside the systemd directory.
  • And below lines using nano myscript.sh
Description=My Script

[Service]
ExecStart=/path/to/myscript.sh
WorkingDirectory=/path/to/
StandardOutput=inherit
StandardError=inherit
Restart=always
User=<replace_username>

[Install]
WantedBy=multi-user.target
  • Reload systemd: sudo systemctl daemon-reload
  • Enable the service: sudo systemctl enable myscript.service
  • Start the service: sudo systemctl start myscript.service
  • To check the service status: sudo systemctl status myscript.service

Option 3: Autostart using lxsession

  • Edit the autostart configuration file: nano ~/.config/lxsession/LXDE-pi/autostart
  • Add the following line to automatically start the Python script: @lxterminal -e python3 /path/to/your/script.py
  • Save the file and initiate a system reboot: sudo reboot
 
Read more...