Sunday, November 8, 2026

Chapter 04: Implementing Sails-style Routing

Before moving on to plugins and hooks, I'd like to dive into an interesting concept supported by Sails: controller-based routing. When I say controller-based routing in Sails, I mean defining routes like this in the config/routes.js file:

module.exports.routes = {
  'GET /': 'HomeController.index'
};

Sails automatically maps this route to the index method of the HomeController.js file.

module.exports = {
  index: (req, res, next) => {
    // ...something...
  },
};

I find this very interesting. So, I thought, why not implement this from scratch to understand how it works?

This chapter is part of my book, Understanding and Using Sails.js, which I'm writing and publishing chapter by chapter.

You can read the first few chapters for free on this blog. Visit the book's dedicated page for more information, or head over to Gumroad to purchase a copy and/or support the ongoing writing of this book.

Our implementation will be loosely based on Sails and is not intended for production applications. The code we're going to write is for educational purposes only. So, consider adding proper validation, error handling, and other improvements if you plan to use something similar in a production application.

As you know, Sails is built on top of Express. In other words, the routes we define using the above syntax are eventually registered as regular Express routes using methods such as app.get(), app.post(), and so on. We're not going to use Sails for this exercise. Instead, we'll use Express directly. This will help us understand how a framework can take a configuration object, resolve the corresponding controller action, and register it as a regular Express route.

Let's get started!

---

Let's create a folder named contacts2. Go inside the folder and create a package.json file.

mkdir contacts2
cd contacts2
npm init -y

Install Express (express) as a production dependency because that's the foundation we need to build our web application in Node.js. We'll also install Nodemon (nodemon) as a development dependency (-D) to make the development workflow easier.

npm i -E express
npm i -E -D nodemon

Let's add the dev and start scripts in the package.json file. We'll use Nodemon during development so that the application restarts automatically whenever we make changes. The start script will run the application directly using Node. Also, change the main field to app.js.

{
    "name": "contacts2",
    "version": "1.0.0",
    "description": "",
    "main": "app.js",
    "scripts": {
        "dev": "nodemon app.js",
        "start": "node app.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "type": "commonjs",
    "dependencies": {
        "express": "5.3.0"
    },
    "devDependencies": {
        "nodemon": "3.1.14"
    }
}

We've referred to an app.js file, but we haven't created it yet. Let's create this file.

touch app.js

Open the app.js file and write the following code:

const express = require("express");
const app = express();

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

We can easily run this application in development mode using the dev script.

npm run dev

You should see output similar to this:

[nodemon] starting `node app.js`
Application is up and running on port 3000

With these changes, our basic Express application is up and running.

---

Let's add three routes: GET /, GET /pages/contact, and POST /users to demonstrate our implementation. I'll just return simple messages for all these routes.

const express = require("express");
const app = express();

app.get("/", (req, res, next) => {
    res.json({ message: "home page" });
});

app.get("/pages/contact", (req, res, next) => {
    res.json({ message: "contact us" });
});

app.post("/users", (req, res, next) => {
    res.json({ message: "user created" });
});

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

Test these routes in your browser and/or Insomnia to confirm that they are working correctly. With these changes, our application now supports all three routes.

Now, we're going to change the structure of the application without changing its output.

---

Go ahead and create a routes.js file in the root folder of the project. You could create this file inside a config folder as well, but I always prefer keeping some files in the root folder to get started. I mean, the starting point should be treated as special.

touch routes.js

Open the routes.js file and write the following code:

module.exports = {
    "get /": "HomeController.index",
    "get /pages/contact": "PagesController.contact",
    "post /users": "UsersController.create",
};

We need to create files named after the controllers, such as HomeController.js, PagesController.js, and UsersController.js. We can put these files anywhere we want, but let's put them inside a controllers folder. So, we need to create that folder first.

mkdir controllers
touch controllers/HomeController.js
touch controllers/PagesController.js
touch controllers/UsersController.js

Open HomeController.js and write the following code:

module.exports = {
    index: (req, res, next) => {
        res.json({ message: "home page" });
    },
};

Nothing unusual here. First, we defined the index method and then copied the code we previously had for the GET / route in the app.js file. Let's write similar code for the other two files as well. Open PagesController.js and write the following code:

module.exports = {
    contact: (req, res, next) => {
        res.json({ message: "contact us" });
    },
};

Finally, open UsersController.js and write the following code:

module.exports = {
    create: (req, res, next) => {
        res.json({ message: "user created" });
    },
};

With these changes, our route definitions and their corresponding controller actions are ready. Next, we need to connect them.

---

In the app.js file, go ahead and remove the three route definitions, as we've moved that code into separate files.

const express = require("express");
const app = express();

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

To call methods from our controller files, we first need to import them. For this, we can use the require-all npm package. This package loads all the files from a directory and makes them available through an object.

Go ahead, stop the server, and install this package.

npm i -E require-all

As mentioned in the package documentation, we can write the following code:

const controllers = require("require-all")({
    dirname: __dirname + "/controllers",
    filter: /(.+Controller)\.js$/,
});

The controllers object now contains references to the modules loaded from the controllers folder. For example, to get a reference to the index method from HomeController, we can simply write:

controllers.HomeController.index()

Let's use the require-all package in our app.js file and load all the controllers.

const express = require("express");
const app = express();

const controllers = require("require-all")({
    dirname: __dirname + "/controllers",
    filter: /(.+Controller)\.js$/,
});

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

With this, we have figured out how to load our controllers dynamically. Next, we need to fetch the route definitions from the routes.js file and attach the corresponding methods to each route. Let's simply require the routes.js file to fetch all the routes.

const express = require("express");
const app = express();

const controllers = require("require-all")({
    dirname: __dirname + "/controllers",
    filter: /(.+Controller)\.js$/,
});

const routes = require("./routes");

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

We're going to use a for...in loop to iterate over the routes object.

const express = require("express");
const app = express();

const controllers = require("require-all")({
    dirname: __dirname + "/controllers",
    filter: /(.+Controller)\.js$/,
});

const routes = require("./routes");

for (let route in routes) {
    // We'll process each route here.
}

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

The route is the key, and it contains two things: the HTTP method and the route path.

For example:

"get /pages/contact": "PagesController.contact"

We need to extract both pieces of information from this string. To extract the HTTP method, we can use a regular expression like this:

const verbExpr = /^(get|post|put|delete)\s+/i;
const match = route.match(verbExpr);
const verb = match ? match[1].toLowerCase() : null;

The first line defines a regular expression that matches four HTTP methods. The second line checks whether the route matches that expression. Finally, we extract the HTTP method and store it in the verb variable. The i flag makes the matching case-insensitive. We convert the extracted method to lowercase because we'll use it to access the corresponding Express method.

Let's add these lines to our app.js file.

const express = require("express");
const app = express();

const controllers = require("require-all")({
    dirname: __dirname + "/controllers",
    filter: /(.+Controller)\.js$/,
});

const routes = require("./routes");

for (let route in routes) {
    const verbExpr = /^(get|post|put|delete)\s+/i;
    const match = route.match(verbExpr);
    const verb = match ? match[1].toLowerCase() : null;
}

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

Next, we need to extract the route path. This is as simple as replacing the HTTP method and the following whitespace with an empty string. Whatever remains is the route path.

const express = require("express");
const app = express();

const controllers = require("require-all")({
    dirname: __dirname + "/controllers",
    filter: /(.+Controller)\.js$/,
});

const routes = require("./routes");

for (let route in routes) {
    const verbExpr = /^(get|post|put|delete)\s+/i;
    const match = route.match(verbExpr);
    const verb = match ? match[1].toLowerCase() : null;
    
    let path = route;
    path = path.replace(verbExpr, "");
}

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

We now have the HTTP method and the route path. We still need to figure out which controller method we should call.

---

Even though all the controller methods are available through the controllers object, we cannot call them dynamically using a single string. We need to extract the controller name and method name separately. To do that, we can split the route definition's value using the dot (.) character.

let location = routes[route];
location = location.split(".");

let controllerLocation = location[0];
let methodLocation = location[1];

The controller name and method name are now available separately. We can use them to access the corresponding controller and method from the controllers object.

let controller = controllers[controllerLocation];
let method = controller[methodLocation];

Let's put everything together in our app.js file.

const express = require("express");
const app = express();

const controllers = require("require-all")({
    dirname: __dirname + "/controllers",
    filter: /(.+Controller)\.js$/,
});

const routes = require("./routes");

for (let route in routes) {
    const verbExpr = /^(get|post|put|delete)\s+/i;
    const match = route.match(verbExpr);
    const verb = match ? match[1].toLowerCase() : null;

    let path = route;
    path = path.replace(verbExpr, "");

    let location = routes[route];
    location = location.split(".");

    let controllerLocation = location[0];
    let methodLocation = location[1];

    let controller = controllers[controllerLocation];
    let method = controller[methodLocation];
}

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

With these changes, we now have the HTTP method, route path, and controller method to call.

The only code we need to register the route with Express is:

app[verb](path, method);

It dynamically accesses the corresponding Express method, such as app.get() or app.post(), and passes the route path and controller method as arguments.

Let's add this line to our app.js file to complete the working Express application.

const express = require("express");
const app = express();

const controllers = require("require-all")({
    dirname: __dirname + "/controllers",
    filter: /(.+Controller)\.js$/,
});

const routes = require("./routes");

for (let route in routes) {
    const verbExpr = /^(get|post|put|delete)\s+/i;
    const match = route.match(verbExpr);
    const verb = match ? match[1].toLowerCase() : null;

    let path = route;
    path = path.replace(verbExpr, "");

    let location = routes[route];
    location = location.split(".");

    let controllerLocation = location[0];
    let methodLocation = location[1];

    let controller = controllers[controllerLocation];
    let method = controller[methodLocation];

    app[verb](path, method);
}

app.listen(3000, () => {
    console.log("Application is up and running on port 3000");
});

Go ahead and restart the application. Test all three routes again in your browser and/or Insomnia. You should see the same output as before.

---

The above implementation is not complete. I've intentionally left out many scenarios and improvements. For example:

  • You can support all the HTTP methods, including PATCH, OPTIONS, and HEAD.
  • You can move the route registration logic into a separate file.
  • You can use better names for the variables.
  • You can implement your own version of the require-all package, as this package is quite small and consists of just one file.
  • You can add error checking. What if someone forgets to add a . between the controller name and method name? Or what if they accidentally add a tab instead of a space between the HTTP method and the route path?
  • You can handle cases where the controller or the specified method doesn't exist.

These are just a few ideas. There are plenty of other things we could improve, but I think this is enough for our educational implementation.

Saturday, November 7, 2026

વાર્તાનો અંત

અને (શું પુસ્તકનો) અંત અધૂરો લાગે છે ? ઉકેલ અપાયો નથી ? તોપણ શું ? કોઈપણ પ્રશ્નનો ઉકેલ આપવાનું કામ વાર્તાલેખકનું નથી. ઉકેલ આપનાર એ કોણ ? એ તો ફક્ત પરિસ્થિતિની છણાવટ કરે, પ્રશ્નો અણદીઠ પડ્યા છે તેને ઉઠાવી દુનિયાની સામે ધરે; દુનિયાના હૃદયમાં એ પ્રશ્નના અસ્તિત્વનું ભાન અને એ પ્રશ્નના નિકાલની મનોવેદના, ઝંખના, તાલાવેલી જાગ્રત કરે; પોતાને સૂઝતી હોય તેવી કોઈક એક નિર્ણય-દિશા પ્રત્યે આંગળી ચીંધાડે; એથી વધુ એ ન જ કરે – જો એ ડાહ્યો હોય તો. વાર્તાલેખક એ વકીલ નથી, વૈદ પણ નથી, રાજપુરુષ પણ નથી. ઉકેલ શોધવાનું કામ તો સમાજરચનાના અગ્રણીઓનું, વ્યવહારદક્ષોનું, કર્મનિષ્ઠ પુરુષોનું છે.

~ ઝવેરચંદ મેઘાણી, સત્યની શોધમાં પુસ્તકમાંથી

Tuesday, November 3, 2026

મંત્રવિદ્યા

જે મંત્રો વડે પરમાર્થ ઉપરાંત ઈહલૌકિક કાર્યોની સિદ્ધિ થાય, તેને લગતા વિધિ-વિધાનોને મંત્રવિદ્યા કહેવામાં આવે છે. શ્રી શંકર કે શિવજી તેના મુખ્ય પ્રણેતા મનાય છે. તેમણે પાર્વતીજીને જે મંત્રો કહ્યા, તેનો સંગ્રહ તે આગમ. રુદ્રયામલ તેની સ્પષ્ટતા આ પ્રમાણે કરે છે:

आगतं शिववक्त्रेभ्यो, गतं च गिरिजामुखे।
मतं श्री वासुदेवेन, तस्मादागम उच्यते ॥

~ રુદ્રયામલ

"જે શાસ્ત્ર શિવજીના મુખમાંથી નીકળીને પાર્વતીજીના મુખમાં ગયું, અર્થાત્ અવસ્થિત થયું છે અને જે વાસુદેવને એટલે વિષ્ણુને પણ સંમત છે, તેને આગમ કહેવાય છે."

શાક્તો આ આગમ ગ્રંથોના સમૂહને પંચમવેદ કહે છે, એટલે કે તેને ઋગ્વેદ, યજુર્વેદ, સામવેદ અને અથર્વવેદ જેટલું જ માન આપે છે અને આ કલિયુગમાં તો તેનો જ મુખ્ય આધાર છે, એમ જણાવે છે.

આગમોના મુખ્યત્વે ત્રણ વિભાગો છે. તેમાંના એકને "યામલ" બીજાને "ડામર" અને ત્રીજાને "તંત્ર" કહેવામાં આવે છે. આ ત્રણેય વિભાગમાં અનેક ગ્રંથો છે અને તેમાં સૃષ્ટિ, પ્રલય, દેવતાઓનું પૂજન, સાધન, પુરશ્ચરણ, ષટ્કર્મસાધન, ચતુર્વિધ ધ્યાનયોગ આદિ અનેક બાબતોનું વર્ણન છે. સામાન્ય રીતે આ ગ્રંથોને "તાંત્રિક સાહિત્ય" તરીકે ઓળખવામાં આવે છે.

મંત્રવિદ્યાનો વિકાસ કરવામાં આ સાહિત્યનો ઘણો ફાળો છે, પરંતુ તેણે વ્યાપક બનવાના મોહમાં વામાચાર આદિ કેટલીક નિંદ્ય પ્રવૃત્તિઓને સ્થાન આપ્યું, તેથી ઔચિત્યભંગ થયો છે અને તે કારણે ધર્મ–નીતિપરાયણ લોકોની તેના પ્રત્યેની માનદ્રષ્ટિ ઓસરી ગઈ છે, એટલું જ નહિ પણ તેના પ્રત્યે તિરસ્કારભરી ઉપેક્ષાવૃત્તિ પ્રવર્તી રહી છે. "તાંત્રિક એટલે મેલી વિદ્યાવાળા, તેનું નામ મૂકો." એ આજના ભદ્ર લોકોના મન ઉપરની છાપ છે અને તેણે સર્વ હિતકારી મંત્રવિદ્યાના પ્રચારને મોટું નુકશાન પહોંચાડ્યું છે, એમ કહેવામાં જરા પણ અત્યુક્તિ નથી.

~ મંત્ર દિવાકર, લેખક: શ્રી ધીરજલાલ ટોકરશી શાહ, શતાવધાની પંડિત

Monday, November 2, 2026

મંત્રયોગ

યોગની સાધના કરવા માટેના જે ઉપાયો, તેને અંગ કહેવામાં આવે છે. તેની સંખ્યા સંપ્રદાય પરત્વે જુદી જુદી છે. મહર્ષિ પતંજલિએ યોગશાસ્ત્રમાં આઠ અંગોનું વર્ણન કરેલું છે, જ્યારે મંત્રયોગના પુરસ્કર્તાઓએ તેનાં સોળ અંગો માનેલાં છે. તે અંગે તેમણે જણાવ્યું છે કે—

भवन्ति मन्त्रयोगस्य षोडशाङ्गानि निश्चितम् ।
यथा सुधांशोर्जायन्ते कलाः षोडश शोभनाः ॥
भक्तिः शुद्धिश्चाऽऽसनञ्च पञ्चाङ्गस्याऽपि सेवनम् ।
आचारधारणे दिव्यदेशसेवनमित्यपि ॥
प्राणक्रिया तथा मुद्रा तर्पणं हवनं बलिः ।
यागो जपस्तथा ध्यानं समाधिश्चेति षोडश ॥

~ મંત્રયોગ સંહિતા

"જેમ ચંદ્રમાને સુંદર સોળ કળાઓ હોય છે, તેમ મંત્રયોગને પણ સોળ કળાઓ છે. તે આ પ્રમાણે : (૧) ભક્તિ, (૨) શુદ્ધિ, (૩) આસન, (૪) પંચાંગસેવન, (૫) આચાર, (૬) ધારણા, (૭) દિવ્યદેશસેવન, (૮) પ્રાણક્રિયા, (૯) મુદ્રા, (૧૦) તર્પણ, (૧૧) હવન, (૧૨) બલિ, (૧૩) યાગ, (૧૪) જપ, (૧૫) ધ્યાન અને (૧૬) સમાધિ."

૧. ભક્તિ: ઇષ્ટદેવ અને ગુરુ પ્રત્યે પરમ શ્રદ્ધા અને સમર્પણ ભાવ.
૨. શુદ્ધિ: શરીર, મન, સ્થાન અને પૂજા સામગ્રીની પવિત્રતા.
૩. આસન: મંત્ર જાપ વખતે બેસવા માટેની સ્થિર અને સુખદાયક સ્થિતિ.
૪. પંચાંગ સેવન: મંત્રના પાંચ અંગો (પટલ, પદ્ધતિ, કવચ, સહસ્ત્રનામ અને સ્તોત્ર) નો પાઠ કરવો.
૫. આચાર: સદાચાર, નિયમિતતા અને સાત્વિક જીવનશૈલીનું પાલન.
૬. ધારણા: ઇષ્ટદેવના સ્વરૂપ કે મંત્રના અક્ષરો પર મનને એકાગ્ર કરવું.
૭. દિવ્યદેશ સેવન: પવિત્ર અને એકાંત સ્થળો (જેમ કે નદી કિનારો, ગુફા કે મંદિર) માં સાધના કરવી.
૮. પ્રાણક્રિયા: શ્વાસોચ્છ્વાસ પર નિયંત્રણ મેળવવું (પ્રાણાયામ).
૯. મુદ્રા: સાધના દરમિયાન હાથ કે શરીરની વિશેષ આકૃતિઓ કે અંગવિન્યાસ ધારણ કરવા.
૧૦. તર્પણ: મંત્રના દેવતા અને ઋષિઓને જળ અર્પણ કરવું.
૧૧. હવન: મંત્ર બોલીને અગ્નિમાં આહુતિ આપવી (યજ્ઞ કરવો).
૧૨. બલિ: બલિ એટલે દેવતા પ્રત્યેનું સમર્પણ. તે બાહ્યભાવે ફળ-ફૂલ તથા નૈવેદ્યની સામગ્રી અર્પણ કરવાથી થાય છે અને અભ્યંતરભાવે તેમના પ્રત્યે પરમ શ્રદ્ધા રાખી સમર્પિત થઈ જવાથી થાય છે.
૧૩. યાગ: ઇષ્ટદેવની માનસિક કે બાહ્ય વિધિપૂર્વક પૂજા-અર્ચના કરવી.
૧૪. જપ: મંત્રનું વારંવાર એકાગ્રતાપૂર્વક રટણ કે આવર્તન કરવું.
૧૫. ધ્યાન: ઇષ્ટદેવના દિવ્ય સ્વરૂપનું સતત ચિંતન કરવું.
૧૬. સમાધિ: સાધનાની સર્વોચ્ચ સ્થિતિ, જેમાં મંત્ર, દેવતા અને સાધક ત્રણેય એકરૂપ થઈ જાય છે.

પરંતુ આજે આ સોળ અંગોનું આલંબન લઈને મંત્રયોગ સિદ્ધ કરનારા કેટલા? એ વિચારણીય છે. આપણને લાગે છે કે આ ક્રિયાઓ કંઈક લાંબી અને કઠિન જણાતાં તાંત્રિક યુગમાં તેમાંની સારભૂત ક્રિયાઓ લઈને મંત્ર-સાધનાની પદ્ધતિને સરળ બનાવવામાં આવી છે.

Sunday, November 1, 2026

Chapter 03: Extra Functionalities

In the previous chapters, we created a Sails application and customized it to our needs. We also saw how we can change some of the default configurations provided by Sails.

Before we move forward, I’d like to discuss some of the functionalities that Sails provides out of the box. Personally, I think some of these functionalities are extra. By extra, I mean that they are useful, but they don’t necessarily need to be part of the framework.

This chapter is part of my book, Understanding and Using Sails.js, which I'm writing and publishing chapter by chapter.

You can read the first few chapters for free on this blog. Visit the book's dedicated page for more information, or head over to Gumroad to purchase a copy and/or support the ongoing writing of this book.

I believe a framework is nothing more than reusable code and some common conventions that its creators decide on our behalf. The idea is to save us from writing the same code again and again. But does every useful piece of code need to be part of the framework?

Let’s take a look at some of the functionalities Sails provides and see what happens when we don’t need them.

---

Blueprint is one of the interesting features of Sails. It automatically provides routes and actions for our models, so we can perform common CRUD operations without writing the code ourselves.

Let’s understand this with an example. Go ahead and run the application first. We have the Contact model. So, in your browser (or GUI API client), visit the following URL.

http://localhost:3000/contact/create?firstName=Kai&lastName=Doe

You should see a response like this:

{
    "id": 1,
    "firstName": "Kai",
    "lastName": "Doe"
}

This is what I meant when I said that Blueprint automatically provides routes and actions for our models, allowing us to perform common CRUD operations without writing the code ourselves. If you now visit the home page, you will notice that we’re already seeing the result of Contact.find() in the console.

For a given model, Sails provides Blueprint actions such as find, findOne, create, update, replace, destroy, populate, add, and remove without requiring us to write them ourselves. For example, to delete the contact we just created, visit the following URL in your browser.

http://localhost:3000/contact/destroy/1

It will return the deleted contact. If you visit the same URL again, you’ll get a 404 response because the contact with that ID no longer exists.

{
    "id": 1,
    "firstName": "Kai",
    "lastName": "Doe"
}

Sounds good, right? But what if we want to write all those operations ourselves? We can do that, too. We can define our own routes and controller actions and write whatever logic we need. That’s what we did when we defined a root route that logs the result of the Contact.find() method.

Of course, Blueprint provides much more than this simple example. It saves us from writing repetitive code, and it can be useful when we’re building an API quickly. But I don’t think it’s essential to the framework itself. If we don’t need it, we can disable Blueprint routes in config/blueprints.js.

We don’t have a config/blueprints.js file yet. Let’s create one.

touch config/blueprints.js

Open blueprints.js and write the following code.

module.exports.blueprints = {
    actions: false,
    rest: false,
    shortcuts: false,
};

These options allow us to disable different types of Blueprint routes:

  • actions disables action shadow routes.
  • rest disables REST blueprint routes.
  • shortcuts disables shortcut routes.

With these options set to false, Sails won’t automatically create those Blueprint routes. Our explicitly defined routes will continue to work.

One thing worth mentioning: shortcut routes are intended for development convenience and should not be enabled in production. They allow us to perform operations through URLs without writing our own routes and controllers.

---

Sails comes with a built-in asset pipeline. It uses Grunt to process assets and move them into the directory from which they can be served to the browser. This is very useful when we want to compile Sass into CSS, combine JavaScript files, or minify assets before deploying our application.

But those days are mostly gone. Have you witnessed many new projects using the traditional approach, where we build a web application using an MVC framework, write SCSS alongside our views, or use CoffeeScript instead of JavaScript? Nowadays, backends are often used to provide APIs, while frontend applications are developed separately. And even if you disagree with that approach, the ecosystem has moved towards other solutions such as Webpack, Vite, esbuild, Parcel, and so on.

I don’t have a problem with Grunt or similar solutions. I personally like these tools and technologies. The problem is that developers are moving quickly towards newer solutions. So quickly that many developers don’t want to learn older, but proven and mature, technologies.

I’ve witnessed projects that were beautifully written, well-maintained, and used for a long time, only to see the company plan to rewrite them using the next popular technology because it was becoming difficult to find developers who knew the existing technology.

Again, we can use a separate tool to manage our frontend assets. We can use Vite, Webpack, or any other tool we prefer. We can even keep our frontend application in a separate project.

If our Sails application only provides an API to a React, Vue, or mobile application, we might not need the built-in asset pipeline at all. Sails allows us to disable the Grunt hook. For example, we can add the following configuration to .sailsrc.

{
    "hooks": {
        "grunt": false
    }
}

This disables the built-in Grunt hook. We can now manage asset compilation outside Sails.

One thing to remember: disabling the hook also means Sails won’t perform the asset processing that the hook normally handles. If our application depends on those tasks, we need to replace them with another solution.

---

Realtime communication is another feature Sails provides out of the box. Sails uses Socket.IO to provide realtime communication between the server and clients. It uses WebSocket when possible and provides additional functionality on top of it. For example, imagine we're building a chat application. When one user sends a message, we want to deliver it to other connected users without asking them to refresh the page. Realtime communication is useful for this kind of application.

But what if we're building a simple REST API? Do we need WebSocket support? No. We can build the entire application using regular HTTP requests. For example, we can define a route that returns a list of contacts and consume it using fetch() from the frontend. There is no need to establish a persistent socket connection.

If we don't need socket support, we can disable the sockets hook through .sailsrc.

{
    "hooks": {
      "sockets": false
    }
}

This disables Sails' built-in socket functionality. Our regular HTTP routes can still do their job.

I like the fact that Sails provides realtime communication without requiring us to build everything from scratch. But I also think it should remain optional. Not every application needs it.

---

Now let's talk about Node Machines. Node Machines provide a standard way to define reusable functions, describe their inputs, and specify their possible outcomes. The idea is to make functions more predictable and easier to reuse across projects. For example, imagine we want to add two numbers. We can write a regular JavaScript function.

function add(a, b) {
    return a + b;
}

That's perfectly fine. We don't need a framework to add two numbers! But let's say we want to define the inputs and describe the possible outcomes in a standard way. We can use the machine package.

You don't have to install the package or write the code yourself. It's here just for explanation.

First, install it.

npm install machine

Now let's define our function as a machine.

const Machine = require("machine");

const add = Machine.build({
    identity: "add",

    inputs: {
        a: {
            type: "number",
            required: true,
        },
        b: {
            type: "number",
            required: true,
        },
    },

    exits: {
        success: {
            outputType: "number",
        },
    },

    fn: function (inputs, exits) {
        return exits.success(inputs.a + inputs.b);
    },
});

The function now has a defined interface: it expects two numbers and returns their sum through the success exit. This is a small example, but the same idea can be useful when building larger reusable operations.

This looks good in theory, especially in a small example where the code itself explains everything. But would you write this much code when building an application? Do you think this JavaScript code is readable? I don't think so. We can use ordinary JavaScript functions, promises, and async/await instead.

Node Machines are an additional programming model. Some developers might like the structure they provide, while others might prefer plain JavaScript. Personally, I'd rather have this kind of functionality available as a separate package instead of making every developer learn it as part of the framework.

---

Internationalization, often shortened to i18n, is the process of preparing an application to support multiple languages and locales. For example, we might want to show Hello, world! to English-speaking users and નમસ્તે, દુનિયા! to Gujarati-speaking users. We could write our own translation functions and store translations in JSON files. Alternatively, we could use an existing internationalization package. Sails provides this functionality out of the box.

Let's see how it works.

First, let's create a config/i18n.js file and define the languages our application supports.

touch config/i18n.js

Open config/i18n.js and write the following code.

module.exports.i18n = {
    locales: ["en", "gu"],
    defaultLocale: "en",
};

We're telling Sails that our application supports English (en) and Gujarati (gu). English is our default language. Now, we need to provide the translations. Sails looks for translation files in the config/locales directory by default. Let's create two files: en.json and gu.json.

In the en.json file, write the following:

{
    "hello": "Hello, world!"
}

Write the following in the gu.json file.

{
    "hello": "નમસ્તે, દુનિયા!"
}

Notice that both files use the same key, hello, but provide different translations.

Now let's open our views/home.ejs file and replace its existing heading with the following code.

<h1><%= __('hello') %></h1>

That's it! We don't need to write our own translation function. Sails provides the __() function, which looks up the translation for the current locale. Restart the application and visit the home page. By default, you should see the English greeting. If the browser sends a Gujarati language preference, Sails can display the Gujarati greeting instead.

We can test this using curl, too.

curl -H "Accept-Language: gu" http://localhost:3000/

The response should contain the Gujarati greeting, assuming the root route renders our home.ejs view.

We can also explicitly change the locale for a particular request using req.setLocale(). For example, if we want to force Gujarati for the current request, we can do this in a controller action before rendering the view.

module.exports = {
    index: async (req, res, next) => {
        const contacts = await Contact.find();
        console.log("contacts:", contacts);

        const logs = await Log.find();
        console.log("logs:", logs);

        req.setLocale("gu");
        res.render("home");
    },
};

This is useful when we want to let users choose their preferred language instead of relying entirely on their browser settings. But does every application need internationalization? Probably not. If we're building an internal API that only returns language-neutral data, we might not need translation support at all.

I don't think internationalization is a bad feature to have. I just think that it should be possible to use it when we need it, without making it a requirement for every application.

---

We've looked at several functionalities that Sails provides and discussed whether they need to be part of the framework. Some of them, such as Blueprint, can save us from writing repetitive code. Others, such as realtime sockets and asset compilation, are useful only for certain kinds of applications. Node Machines provide another way to structure reusable functions, while internationalization helps us support users who speak different languages.

I don't think there's a single correct answer to whether these features belong in Sails. Framework design involves trade-offs, and different developers will make different choices. What matters to me is that we understand what the framework provides, why it provides it, and whether we actually need those features in our applications. After all, we're using a framework to make our work easier, not to give ourselves more things to learn without a good reason.

And that's exactly why one should understand the framework beyond simply using it!

Wednesday, October 21, 2026

Chapter 02: Customizing Sails Apps

In the previous chapter, we created a small Sails application and explored the basics of its MVC functionality. We saw how to define routes, create controllers and models, and render a view.

In this chapter, we’ll explore some ways to customize a Sails application. We’ll start with simple changes, such as changing the port, and gradually move towards customizing the functionalities that Sails provides.

This chapter is part of my book, Understanding and Using Sails.js, which I'm writing and publishing chapter by chapter.

You can read the first few chapters for free on this blog. Visit the book's dedicated page for more information, or head over to Gumroad to purchase a copy and/or support the ongoing writing of this book.

The idea is to understand how much control Sails gives us over the application without requiring us to modify the framework itself.

---

Let’s start by changing the port. By default, Sails starts the server on port 1337. But what if we want to run our application on a different port? We can pass configuration options to the sails.lift() method in the app.js file. Let’s change the port to 3000.

const sails = require('sails');

sails.lift({
    port: 3000,
});

That’s it! Restart the application, and Sails will start the server on port 3000 instead of the default 1337 port. You can now visit http://localhost:3000 in your browser to access the application. This is a simple example of how we can customize a Sails application by passing configuration options when lifting the server.

---

If you’ve run a Sails application, you’ve probably noticed the ASCII ship displayed in the terminal when the application starts. It’s a nice touch, but we might not always want to see it. For example, we may prefer cleaner console output when running our application. Sails provides the log.noShip option for this purpose. Let’s update the code in our app.js file.

const sails = require('sails');

sails.lift({
    port: 3000,
    log: {
        noShip: true,
    },
});

We’ve added the log configuration object and set noShip to true. Now, Sails won’t display the ship during startup. Notice that we’re still using the same sails.lift() method. We’re simply passing an additional configuration option. Restart the application, and the ship should disappear from the console!

---

When starting the application, you might notice some messages related to sessions in the console. If our sandbox application doesn’t need session support, we can disable the session hook.

When starting the application, you might notice following messages related to sessions in the console. If our sandbox application doesn’t need session support, we can disable the session hook.

debug: Warning: no session secret was set!  In development mode, we'll set this for you,
debug: but session secret must be manually specified in production.
debug: To set up a session secret, add or update it in `config/session.js`:
debug: module.exports.session = { secret: 'extremely-secure-keyboard-cat' }
debug: 
debug: (Or if you don't need sessions enabled, disable the hook.)

Sails uses hooks to organize and extend its functionality. A hook can provide a particular capability to the application, and Sails loads its built-in hooks during startup. Let’s disable the session hook by setting hooks.session to false in the app.js file.

const sails = require('sails');

sails.lift({
    port: 3000,
    log: {
        noShip: true,
    },
    hooks: {
        session: false,
    },
});

We’ve now disabled the session hook in addition to hiding the ship. Keep in mind that disabling the session hook is not merely a way to hide console messages. It also disables session functionality, which may be required by parts of your application. For our experimental sandbox, we can disable it if we don’t need sessions for now. With these options in place, the startup output should be much quieter.

---

Now that we’ve reduced the default startup output, let’s print a message of our own. The sails.lift() method accepts a callback that runs after the application has finished lifting. We can use this callback to print a message when the application is ready.

const sails = require('sails');

sails.lift(
    {
        port: 3000,
        log: {
            noShip: true,
        },
        hooks: {
            session: false,
        },
    },
    () => {
        console.log('Application is up and running on port 3000');
    }
);

We’ve moved the configuration options into the first argument and added a callback as the second argument. Once Sails has finished starting the application, the callback prints our message to the console. If you’re thinking about Express’s app.listen() callback function, you’re right!

---

In the previous example, we used Node’s built-in console.log() method to print our message. However, Sails provides its own logger through sails.log. It supports different log levels, such as info, warn, error, and debug.

Let’s use the info method instead.

const sails = require('sails');

sails.lift(
    {
        port: 3000,
        log: {
            noShip: true,
        },
        hooks: {
            session: false,
        },
    },
    () => {
        sails.log.info();
        sails.log.info('Application is up and running on port 3000');
        sails.log.info();
    }
);

Using the Sails logger keeps our messages within the application’s logging system. This also means that the logger’s configuration, including its log level, can affect which messages appear in the console. You may notice that we’re calling sails.log.info() without any arguments before and after our message. These calls are intended to add some visual spacing around the message.

---

We can make our startup message more informative by including the version of Sails we’re running. Sails exposes its version through sails.version.

Let’s add it to our startup output.

const sails = require('sails');

sails.lift(
    {
        port: 3000,
        log: {
            noShip: true,
        },
        hooks: {
            session: false,
        },
    },
    () => {
        sails.log.info();
        sails.log.info('Application is up and running on port 3000');
        sails.log.info(`Sails v${sails.version}`);
        sails.log.info();
    }
);

Running the application should print the version of Sails we’re using in our application.

---

So far, we’ve been passing all our configuration options directly to sails.lift(). This works, but imagine that we have many more options to configure. Our app.js file could become cluttered with configuration details. Fortunately, Sails supports a .sailsrc file for application configuration. We can move our configuration options into this file and keep app.js clean.

Create a .sailsrc file in the root of the contacts application and add the following configuration:

{
    "port": 3000,
    "log": {
        "noShip": true
    },
    "hooks": {
        "session": false
    }
}

Now we can remove the configuration options from the sails.lift() method, keeping only the callback function in app.js. To load the configurations from the .sailsrc file, we need to import rc from sails/accessible/rc and then call the rc() function with sails as the argument.

All in all, we need to write the following code:

const sails = require('sails');
const rc = require('sails/accessible/rc');

sails.lift(rc("sails"), () => {
    sails.log.info('Application is up and running on port 3000');
    sails.log.info(`Sails.js v${sails.version}`);
});

Go ahead and restart the application. You should see the same output in the console.

---

We can rearrange the locations of models, views, and controllers. Instead of keeping these folders in their current locations, we can have a root-level app folder and put all three folders inside it:

  • app/models
  • app/views
  • app/controllers

To do this, we need to set the values of paths.models, paths.views, and paths.controllers in the .sailsrc file.

Let’s update the configuration:

{
    "port": 3000,
    "log": {
        "noShip": true
    },
    "hooks": {
        "session": false
    },
    "paths": {
        "controllers": "app/controllers",
        "models": "app/models",
        "views": "app/views"
    }
}

Now, move the controllers, models, and views into the app folder. In our existing project, this means moving the relevant folders out of api and into app. After that, rerun the application. You shouldn’t notice any difference in the result. You’ll still see the same output, but with a different folder structure.

Better? :)

---

Let’s shift our focus and customize the Sails application beyond its configuration options. For example, what if I want to use Pug as the template engine instead of EJS? First, we need to install the consolidate package.

npm i -E consolidate

As we’re planning to use Pug, don’t forget to install that as well.

npm i -E pug

View configuration is defined in the config/views.js file. We don’t have this file yet, so let’s create it.

touch config/views.js

Open config/views.js and add the following code:

module.exports.views = {
    extension: 'pug',

    getRenderFn: function () {
        const consolidate = require('consolidate');
        return consolidate.pug;
    },

    layout: false,
};

First, I specified the template extension so that I don’t have to write the extension when using the template with the res.render() method.

Second, I need to tell Sails which render function to use for the given template. If the template engine is supported by Consolidate, it’s quite easy to do: we can return the appropriate render function from getRenderFn(), as Sails suggests.

Finally, Pug has its own way of handling layouts and related functionality. We can explicitly configure the layout behavior, so I’ve set layout to false.

---

Let’s replace the disk-based database with PostgreSQL. For this, you should have PostgreSQL installed on your computer.

First, install the PostgreSQL adapter:

npm i -E sails-postgresql

Next, create the config/datastores.js file.

module.exports.datastores = {
    default: {
        adapter: require('sails-postgresql'),
        url: 'postgres://postgres:password@localhost:5432/contacts',
    },
};

The database URL follows this format:

protocol://user:password@host:port/database

Create a database named contacts in PostgreSQL and then rerun the application. With an appropriate migration strategy configured, Sails can create the contacts table in the contacts database. I know, this looks a bit odd: we have a database named contacts and a table named contacts inside it!

---

Interestingly enough, we can use multiple databases in a single application. For example, we can use MongoDB alongside PostgreSQL.

Let’s install the MongoDB adapter:

npm i -E sails-mongo

Next, add a mongo datastore to config/datastores.js.

module.exports.datastores = {
    default: {
        adapter: require('sails-postgresql'),
        url: 'postgres://postgres:password@localhost:5432/contacts',
    },
    mongo: {
        adapter: require('sails-mongo'),
        url: 'mongodb://localhost:27017/logs',
    },
};

We’ve now configured two datastores: default, which uses PostgreSQL, and mongo, which uses MongoDB.

Let’s create a Log model to work with the MongoDB datastore in Log.js file within app/models.

touch app/models/Logs.js

Open Logs.js and add the following code.

module.exports = {
    datastore: 'mongo',
    attributes: {
        id: {
            columnName: '_id',
            type: 'string',
        },
        action: { 
            type: 'string', 
            required: true,
        },
  },
};

We’ve specified mongo as the datastore for this model. This tells Waterline to use our MongoDB datastore when working with Log.

Let’s use both models in index function of HomeController.js file.

module.exports = {
    index: async (req, res, next) => {
        const contacts = await Contact.find();
        console.log('contacts:', contacts);

        const logs = await Log.find();
        console.log('logs:', logs);

        res.render('home');
  },
};

Here, we’re querying the Contact and Log models separately. The Contact model uses the default PostgreSQL datastore, while the Log model uses MongoDB. This is a simple example of how we can work with multiple databases in the same Sails application.

---

Customization is endless! But let’s stop here. In the next chapter, we’ll take a look at some extra functionalities that Sails provides. I said extra because I personally think these are nice-to-have features that don’t necessarily need to be part of the framework. Again, that’s just my personal opinion, and you might disagree. That’s totally fine with me! :)

Tuesday, October 20, 2026

હઠયોગ

हकारः कीर्तितः सूर्यः ठकारश्चन्द्र उच्यते।
सूर्याचन्द्रमसोर्योगाद्धठयोगो निगद्यते॥
~ सिद्धसिद्धान्तपद्धति, ગોરખનાથ

હ વર્ણ સૂર્ય તરીકે ઓળખાય છે, ઠ વર્ણ ચંદ્ર ઓળખાય છે. આ સૂર્ય અને ચંદ્રનો યોગ-સમન્વય થવાને લીધે હઠયોગ કહેવાય છે.

ત્રણ નાડીઓ ઈડા નાડી ચંદ્રનાડી તરીકે ઓળખાય છે, જયારે પિંગળાનાડી સૂર્યનાડી તરીકે ઓળખાય છે. આ બંનેનું મિલન એટલે કુંડલિની જાગરણ.

ચાર પ્રકારના યોગમાં હઠયોગ બીજા પ્રકારે આવે છે.

मन्त्रयोगो लयश्चैव हठयोगस्तृतीयकः ।
चतुर्थो राजयोगः स्यात् स द्विधा परिकीर्तितः ॥
~ શિવ સંહિતા

મંત્રયોગ, હઠયોગ, લયયોગ, અને ચોથો દ્વેત વગરનો રાજયોગ એમ ચારયોગ છે.

Monday, October 19, 2026

જ્ઞાનની સાત ભૂમિકા

જ્ઞાનની સાત ભૂમિકા છે:

૧. શુભેચ્છા (મોક્ષની ઈચ્છા)
સંસારથી વૈરાગ્ય પામીને મોક્ષ મેળવવાની અને સત્યને જાણવાની તીવ્ર ઈચ્છા.
આ પ્રથમ અવસ્થામાં સાધકને સંસારના ભૌતિક સુખોની નશ્વરતા સમજાય છે. તેના મનમાં "હું કોણ છું? આ જગત શું છે?" તે જાણવાની તીવ્ર જિજ્ઞાસા જાગે છે. તે અજ્ઞાનમાંથી બહાર આવવા માટે સત્સંગ, સદગુરુની શોધ અને આધ્યાત્મિક પુસ્તકોના વાંચન તરફ વળે છે. આ અવસ્થામાં વૈરાગ્યનો જન્મ થાય છે.

૨. વિચારણા (ઊંડાણપૂર્વકનું ચિંતન):
સદગુરુ અને શાસ્ત્રોના શરણે જઈને શ્રવણ, મનન અને આત્મજ્ઞાન પર ગહન ચિંતન કરવું.
શુભેચ્છા જાગ્યા પછી, સાધક ગુરુના શરણે જાય છે અને વેદાંત શાસ્ત્રોનું શ્રવણ કરે છે. ત્યારબાદ તે સાંભળેલા જ્ઞાન પર મનન-ચિંતન અને ધ્યાન કરે છે. શું સત્ય (આત્મા) છે અને શું અસત્ય (જગત) છે તેનો ભેદ પારખવાની ક્ષમતા આ અવસ્થામાં વિકસે છે.

૩. તનુમાનસા (મનની સૂક્ષ્મતા):
મનનું અત્યંત સૂક્ષ્મ થવું અને ઈન્દ્રિયો તથા વાસનાઓનો નાશ થવો.
સતત વિચારણા અને ધ્યાનના પરિણામે સાધકનું મન અત્યંત સૂક્ષ્મ અને એકાગ્ર બને છે. ઇન્દ્રિયોના વિષયો પ્રત્યેની આસક્તિ અત્યંત તનુ એટલે ક્ષીણ થઈ જાય છે. મન બાહ્ય જગતમાંથી હટીને અંતર્મુખી બને છે. આ અવસ્થા સુધી પહોંચેલો સાધક યોગાભ્યાસી કહેવાય છે.

૪. સત્ત્વાપત્તિ (સત્વગુણની પ્રાપ્તિ અને આત્મસાક્ષાત્કાર):
મનની સંપૂર્ણ શુદ્ધિ થવી અને આત્મસ્વરૂપનો સાચો પ્રકાશ (સત્ય) અનુભવવો.
આ અવસ્થામાં રજોગુણ અને તમોગુણ સંપૂર્ણપણે નાશ પામે છે અને માત્ર શુદ્ધ સત્વગુણ જ રહે છે. સાધકને આત્મસ્વરૂપનો સાચો પ્રકાશ દેખાય છે. તેને બ્રહ્મનું વાસ્તવિક જ્ઞાન (આત્મસાક્ષાત્કાર) થાય છે. આ અવસ્થામાં જગત એક સ્વપ્ન જેવું ભાસે છે. અહીં સાધક 'બ્રહ્મવિદ્' કહેવાય છે.

૫. અસંશક્તિ (સંપૂર્ણ અનાસક્તિ):
જગતના કોઈપણ પદાર્થ, કર્મ કે ફળ પ્રત્યે કોઈ જ આસક્તિ ન રહેવી (સંપૂર્ણ નિર્લેપ અવસ્થા).
આત્મજ્ઞાન થયા પછી સાધક જગતના વ્યવહારોમાં રહેવા છતાં કોઈ જ પ્રકારની આસક્તિ કે મોહ ધરાવતો નથી. કર્મ કરવા છતાં કર્મના ફળ પ્રત્યે તેને કોઈ લેપ લાગતો નથી. તે કમળના પાન પર રહેલા જળના બિંદુની જેમ સંસારમાં અલિપ્ત રહે છે. આ અવસ્થા પ્રાપ્ત કરનાર જ્ઞાની 'બ્રહ્મવિદ્વર' કહેવાય છે.

૬. પદાર્થભાવની (પદાર્થોના અસ્તિત્વનો અભાવ):
બાહ્ય પદાર્થોનું અસ્તિત્વ ભૂલાઈ જવું અને અન્ય દ્વારા જગાડવા પર જ વ્યવહારમાં જોડાવું.
આ અવસ્થામાં જ્ઞાનીનું મન બ્રહ્મમાં એટલું લીન થઈ જાય છે કે તેને બાહ્ય જગતના પદાર્થોનું કોઈ ભાન રહેતું નથી. આજુબાજુ શું બની રહ્યું છે તેનો તેને કોઈ ખ્યાલ હોતો નથી. જ્યારે અન્ય લોકો (શિષ્યો કે ભક્તો) તેને જગાડે કે પ્રેરિત કરે, માત્ર ત્યારે જ તે શારીરિક જરૂરિયાત પૂરતો વ્યવહાર કરે છે. આવા મહાત્મા 'બ્રહ્મવિદ્વરીયાન' કહેવાય છે.

૭. તુર્યગા (તુરીયાવસ્થા):
અદ્વૈત અને પરમ શાંતિની સર્વોચ્ચ અવસ્થા, જ્યાં ભેદભાવ સંપૂર્ણ નષ્ટ થઈ જાય છે અને વ્યક્તિ 'જીવનમુક્ત' બની જાય છે.
આ જ્ઞાનની સર્વોચ્ચ અને અંતિમ અવસ્થા છે. તેને 'જીવનમુક્તિ' કહેવામાં આવે છે. આ અવસ્થામાં 'હું' અને 'તું' કે 'બ્રહ્મ' અને 'જગત' એવો કોઈ ભેદ રહેતો નથી; બધું જ એકાકાર થઈ જાય છે. અન્ય લોકોના જગાડવા છતાં પણ તેઓ સમાધિમાંથી બહાર આવતા નથી. તેઓ દેહમાં હોવા છતાં વિદેહ (દેહરહિત) અવસ્થાનો અનુભવ કરે છે. આવા સિદ્ધ પુરુષ 'બ્રહ્મવિદ્વરિષ્ઠ' કહેવાય છે.

આ જ્ઞાનની ભૂમિકાની આવસ્થાને આધારે યોગી કઈ કક્ષાએ છે, એ નક્કી થાય છે અને જરૂરી માર્ગદર્શન અથવાતો ઉપાધિ જેવી કે, યોગી, ઋષિ, મહર્ષિ, પરમહંસ વગેરે પામે છે.

Sunday, October 18, 2026

Chrome અને Edge XSLT કાઢી રહ્યા છે

Chrome અને Microsoft Edge જેવા બ્રાઉઝર માં લાંબા સમયથી રહેલી XSLT સુવિધા દૂર થવાની તૈયારીમાં છે. XSLTનો ઉપયોગ XMLમાં રહેલા ડેટાને HTML જેવા બીજા સ્વરૂપમાં ફેરવવા માટે થતો હતો. ઉદાહરણ તરીકે, કોઈ વેબસાઇટ XML ફાઇલમાં માહિતી રાખે અને browser XSLTની મદદથી તેને વાંચી શકાય તેવા પેજમાં ફેરવે. Googleના જણાવ્યા મુજબ, Chrome 158માં 17 નવેમ્બર, 2026થી સામાન્ય વપરાશકર્તાઓ માટે આ સુવિધા બંધ કરવાની યોજના છે.

આ ફેરફાર પાછળનું મુખ્ય કારણ સુરક્ષા અને ઘટતો ઉપયોગ છે. Chromeમાં XSLT માટે વપરાતી જૂની libxslt લાઇબ્રેરી જટિલ છે અને તેમાં સુરક્ષાની ખામીઓ મળી આવી છે. આજે મોટા ભાગની વેબ એપ્લિકેશન્સ ડેટા મેળવવા માટે JSON અને પેજ બનાવવાં JavaScriptનો ઉપયોગ કરે છે, તેથી browserમાં XSLTની જરૂર પહેલાં કરતાં ઘણી ઓછી રહી છે.

Saturday, October 17, 2026

ફિલાડેલ્ફિયામાં ડિલિવરી રોબોટનો રસ્તો રોકવા બદલ મહિલાની ધરપકડ

ફિલાડેલ્ફિયાના સેન્ટર સિટીમાં કેરોલિન માર્વિન નામની મહિલાની ડિલિવરી રોબોટનો રસ્તો રોકવા બદલ ધરપકડ કરવામાં આવી છે. પોલીસના જણાવ્યા મુજબ, 1200 બ્લોક ફિલબર્ટ સ્ટ્રીટ પાસે માર્વિને વારંવાર રોબોટનો રસ્તો અટકાવ્યો અને અધિકારીઓની ખસવા અંગેની સૂચનાઓનું પાલન ન કર્યું. તેમના પર અવ્યવસ્થિત વર્તનનો આરોપ મૂકાયો છે.

માર્વિન કહે છે કે તેઓ રોબોટ્સનો વિરોધ કરે છે, કારણ કે તેમના મતે તે કામદારોની નોકરીઓ લઈ રહ્યા છે. તેઓ આ વિરોધને જાહેર અભિવ્યક્તિનો અધિકાર માને છે અને આગળ પણ વિરોધ ચાલુ રાખવાની વાત કરે છે. આ ઘટનાનો વીડિયો ઑનલાઇન વાયરલ થયો છે.

~ સ્ત્રોત - 6abc.com સમાચાર.

Friday, October 16, 2026

ChatGPT કઈ રીતે કામ કરે છે?

તમે ChatGPT ને પ્રશ્ન પૂછો છો અને તે તરત જ જવાબ આપી દે છે. પણ શું તમે ક્યારેય વિચાર્યું છે કે અંદર ખરેખર શું થાય છે? ઘણા લોકો માને છે કે ChatGPT એક વિશાળ જ્ઞાનકોશ છે — જેમાં દરેક પ્રશ્નનો જવાબ પહેલેથી ભરેલો છે. જ્યારે તમે પ્રશ્ન પૂછો, ત્યારે તે યોગ્ય ખાનું ખોલીને જવાબ કાઢી આપે છે.

પણ સાચી વાત એથી ઘણી અલગ છે. ChatGPT પાસે કોઈ જવાબોની યાદી નથી. તે દરેક જવાબ ત્યારે જ, ત્યાં જ, શબ્દ-દર-શબ્દ બનાવે છે.

આ લેખમાં આપણે સમજીશું કે આ ખરેખર કેવી રીતે થાય છે સાદી ભાષામાં ટેકનિકલ પળોજણમાં નહીં પડીએ.

ચાલો એક ઉદાહરણથી શરૂઆત કરીએ. જ્યારે તમે ChatGPT માં લખો છો કે,

"France ની રાજધાની શું છે?" ત્યારે ChatGPT ને આ "પ્રશ્ન" દેખાતો નથી. તેને ફક્ત આ શબ્દો દેખાય છે:

France / ની / રાજધાની / શું / છે / ?

અને પછી તે પોતાને પૂછે છે: "આ શબ્દો પછી સૌથી સંભવિત આગળનો શબ્દ કયો હશે?" તે અનુમાન કરે છે: "The" આ ઉપરથી હવે શબ્દોની શ્રેણી બની:

France / ની / રાજધાની / શું / છે / ? / The

ફરી પૂછે છે: "હવે આગળનો શબ્દ?" પાછું અનુમાન કર્યું કે સંભવિત શબ્દ હશે: "capital".

France / ની / રાજધાની / શું / છે / ? / The / capital

અને અંતે બને છે:

"The capital of France is Paris."

બસ, આટલું જ.ChatGPT એ ક્યાંય નક્કી નથી કર્યું કે "મારે આ પ્રશ્નનો જવાબ આપવો છે." તેણે ફક્ત શબ્દ પર શબ્દ જોડ્યા — અને પરિણામ જવાબ જેવું લાગ્યું.

જો તમને પ્રશ્ન થાય કે આ રીતે જવાબ સાચો કેવી રીતે આવે તો એનો જવાબ છે - તાલીમ. ChatGPT ને ઈન્ટરનેટના અબજો લખાણ પર તાલીમ આપવામાં આવી છે. એ લખાણમાં અસંખ્ય વાર એવું બન્યું છે કે: રશ્ન પછી → જવાબ આવ્યો. તેથી જ્યારે મોડેલને પ્રશ્ન દેખાય, ત્યારે તેના માટે "સૌથી સંભવિત આગળનો ભાગ" જવાબ જ હોય છે.

તમને દેખાય છે: એક પ્રશ્ન, પછી એક જવાબ મોડેલને દેખાય છે: શબ્દોની એક લાંબી શ્રેણી, જે તેને ફક્ત લંબાવવાની છે. તમને લાગે છે કે તેણે "જવાબ આપ્યો." પણ ખરેખર તેણે ફક્ત "લખાણ ચાલુ રાખ્યું છે".

તમારા ફોનમાં જે autocomplete છે તે યાદ છે?

તમે લખો: "હું ઘરે જાઉં..."

ફોન સૂચવે: "...છું"

બસ, ChatGPT એ જ autocomplete છે — પણ:

  • તમારા ફોન કરતાં લાખો ગણું વધુ તાલીમ પામેલું
  • સેકન્ડના લાખો શબ્દો ની ઝડપે ચાલે છે
  • આખું ઈન્ટરનેટ વાંચી ચૂક્યું છે

એટલે જ તમારો ફોન "છું" સૂચવે છે, જ્યારે ChatGPT આખો નિબંધ લખી નાખે છે. સિદ્ધાંત એક જ છે — ફક્ત સ્કેલ વિશાળ છે.

અહીં તમારે ખાસ યાદ રાખવાનું છે કે, ChatGPT અર્થ સમજતું નથી. તે ફક્ત એ જાણે છે કે "આ શબ્દો પછી, સામાન્ય રીતે આ શબ્દો આવે છે."

એટલે જ તે:

  • ખોટી માહિતી પણ આત્મવિશ્વાસથી કહી શકે
  • વિરોધાભાસી વાતો કરી શકે
  • નકલી તથ્યો (references, તારીખો, નામ) બનાવી શકે

કારણ સાદું છે: તે "સંભવિત શબ્દો" જોડે છે, "સાચા શબ્દો" નહીં. મોટા ભાગે સંભવિત અને સાચું એક જ હોય છે — તેથી જવાબ સાચો આવે છે. પણ જ્યાં સંભવિત અને સાચું અલગ પડે, ત્યાં તે ભૂલ કરે છે. આ ઘટનાને "hallucination" (ભ્રમ) કહેવાય છે.

ChatGPTઆટલું ઉપયોગી એટલા માટે છે કે, એ autocomplete અદ્ભુત રીતે કરી જાણે છે. કેમ કે, તેણે તે લાખો લેખો, પુસ્તકો, સંવાદોમાંથી શીખ્યું છે

તેથી તેનું "સૌથી સંભવિત આગળનું" ઘણી વાર ખરેખર ઉપયોગી નીકળે છે. લખવામાં, સમજાવવામાં, અનુવાદ કરવામાં, વિચારો ગોઠવવામાં — તે મદદરૂપ થાય છે.

Thursday, October 15, 2026

Daemon

કોમ્પ્યુટરમાં પ્રોસેસ(=process) શબ્દ આવે છે. જેનો મતલબ સરળ ભાષામાં કહીએતો એવો સોફ્ટવેર જે સતત પડદા પાછળ(=background) ચાલતો હોય અને જેને માણસના હસ્તક્ષેપ/દખલ જરૂર ના પડે. ઉદાહરણ રૂપે, mysqld, systemd, sshd, વગેરે.

આ દરેક પ્રોસેસની નામ પાછળ 'd' લાગે છે, જેનો મતલબ daemon(=ડિમન) થાય છે. આ શબ્દને સમાંતર એક બીજી શબ્દ પણ અંગ્રેજીમાં છે અને એ છે demon(=ડિમન) એટલે દૈત્ય થાય છે. આ શબ્દ ગ્રીક શબ્દ daimon(=ડિમોન) પરથી ઉતરી આવેલ છે, જેનો મતલબ અલૌકિક અને દૈત્ય તો ના કહી શકાય પણ એની હારનો મતલબ થાય છે. તો શું કોમ્પ્યુટરમાં પ્રોસેસ બધી દૈત્ય છે, અને સતત ચાલુ રહીને કાંડ કરે છે. તો કે, ના એવું નથી.

આ 'd' એટલે કે ડિમનનો મતલબ જ થાય છે કે, સતત માણસના હસ્તક્ષેપ વગર કામ કરતુ પ્રાણી. અહીં એ પ્રોસેસ છે એટલે આપણે એને પ્રોસેસ ડિમન કહી છે અને એ સોફ્ટવેરના નામ પાછળ 'd' લગાડીએ છીએ. આ ડિમન શબ્દ મેક્સવેલના ડિમન(=demon) પરથી આવેલો છે. મેક્સવેલએ એક કલ્પનાત્મક પ્રયોગ રજુ કર્યો. આ પ્રયોગમાં એને એક એવા બુદ્ધિશાળી પ્રાણીની વાત કરી જે અણુઓની ગતિ જોવી એને એક અથવા બીજા બોક્સમાં જવા દે. આ કામ એને સતત કરતા રહેવનું, મેક્સવેલના હસ્તક્ષેપ વગર. તો અહીં એક કલ્પનાત્મક પ્રાણી સતત ક્રિયા કરતુ રહે, એક સહાયકના રૂપમાં. એવુ જ કામ આ બધી પ્રોસેસનું છે આથી આ બધી પ્રોસેસને ડિમન નામ આપવામાં આવ્યું.

એવું સાંભળવામાં આવ્યું છે (અને ખોટું પણ હોઈ શકે) કે મેલી વિદ્યામાં જે તે વ્યક્તિ ઝોળિયું-ઝાપટિયું કોઈની પાછળ એને હાનિ પહોંચાડવા મોકલે. એ પણ સતત પોતાનું કામ (બીજાને હાનિ પોહાચાડવાનું) કરતુ રહે એને પણ હસ્તક્ષેપની જરૂર ના પડે. તો આ ઝોળિયું-ઝાપટિયું પણ daemon(=ડિમન) જ થયુંને?!

Wednesday, October 14, 2026

ફ્રાન્સમાં ફ્રિજ પર સાઈબર હુમલો

તારીખ ૧૨ ઓક્ટોબર ૨૦૨૬ ની રાત્રે ફ્રાન્સમાં સેંકડો સુપરમાર્કેટ પર મોટો સાઈબર હુમલો થયો છે, જેના કારણે ફ્રિજ અને ફ્રીઝરના તાપમાનમાં અચાનક વધારો થયો છે. હેકર્સે ફ્રિજ અને ફ્રીઝરનું તાપમાન વધારીને ૫૦° સેલ્સિયસ સુધી કરી દીધું હતું, જેના લીધે નાની આગના બનાવો બન્યા અને લાખો યુરોની તાજી તેમજ ફ્રોઝન (બરફવાળી) ખાદ્યસામગ્રી બગડી ગઈ.

Intermarché, Coopérative U, Carrefour, Monoprix અને E. Leclerc સહિત ૪૦૦થી વધુ સુપરમાર્કેટ આનાથી પ્રભાવિત થયા છે. આના પર વધુ તપાસ ચાલી રહી છે પણ હાલ એટલી વાત બહાર આવી છે કે, ડેનિશ કંપની Danfoss ના (AK-SM 800A કંટ્રોલર જેવા) જૂના અને સૉફ્ટવેર અપડેટ વિનાના રેફ્રિજરેશન સિસ્ટમ્સની નબળાઈનો હેકર્સે લાભ લઈને આ સાઈબર હુમલો કરવામાં આવ્યો હોવાનું મનાય છે.

જાનહાનિ નથી થઈ એમ ગણી આને સામા્નયમાં નાં ખપાવી શકાય કેમ કે, આફતના સમયમાં જો ખાદ્યસામગ્રી આ રીતે સાચવીને રાખવામાં આવી હોય અને આમ સાયબર હુમલાથી એને નુકસાન કરવામાં આવે તો આફત વધુ વિકરાળ બને અને વિનાશ નોતરે.

Monday, October 12, 2026

ફટ્

તંત્રમાં ખૂબ જ પ્રખ્યાત ફટ્ નામનો રહસ્યમય ધ્વનિ, વાજસનેયીમાં જોવા મળે છે! સંહિત અપસ્તંબ શ્રૌતસૂત્રમાં, ફટ્નો ઉપયોગ અભિસારમાં કેટલીક દાંડીઓ ચઢાવવા માટે થાય છે. ~ Encyclopedia of Tantra Vol. 1 - Sadhu Santdev.

મંત્રતંત્રમાં વપરાતો શબ્દ; કર્મકાંડમાં વપરાતો શબ્દ; યજ્ઞમાં દિગ્બંધ માટે એટલે દિશાઓ તરફથી થતાં વિઘ્નો અટકાવવા માટે વપરાતા મંત્રના અંતનો અવ્યય. ~ ભગવદ્ગોમંદલ માંથી.

Sunday, October 11, 2026

રોગનું દમન અને તેની લાંબા ગાળાની અસર

ડોકટરનું કામ દરદીનો રોગ કાયમને માટે દૂર કરવાનું છે. છતાં મોટા ભાગના કિસ્સામાં આવું બનતું નથી. કેટલીક વાર દવાઓ રોગને દબાવી રાખે છે. આમાં જ્ઞાનતંતુઓને નબળા બનાવી દેવાથી દુખાવો કે રોગનો સંદેશો મગજ સુધી પહોંચતો નથી. તેથી શરીરમાં રોગ હોવા છતાં રોગ અથવા દુખાવો કાયમનું ઘર કરી શરીરમાં રહે છે. દરદીને આ બાબતની કશી જાણકારી કે સંદેશો મળતો નથી.

કેટલાક દરદીઓના કિસ્સામાં રોગ જેમ જેમ જૂનો થતો જાય છે. તેમ તેમ કાયમનું ઘર બનાવી શરીરમાં જ રહી જાય છે.

~ ચક્ર શક્તિ ચિકિત્સા દ્વારા રોગ મુક્તિ, લેખક: ડૉ. રસિક છ. શાહ

Monday, October 5, 2026

Chapter 01: Sails as MVC Framework

We need a sandbox application in the Sails framework to conduct some experiments. Let's call it contacts, as it'll be a contact management system application.

This chapter is part of my book, Understanding and Using Sails.js, which I'm writing and publishing chapter by chapter.

You can read the first few chapters for free on this blog. Visit the book's dedicated page for more information, or head over to Gumroad to purchase a copy and/or support the ongoing writing of this book.

The steps we're going to follow to create a Sails app are somewhat unusual. We're not going to use the Sails CLI or the global Sails package. Instead, we'll create a folder and install Sails as a dependency.

mkdir contacts
cd contacts
npm init -y
npm i -E sails

Let's create an app.js file and then write the following code.

const sails = require("sails")

sails.lift();

We first required the sails package and then called the .lift() method to start the server on the default port, 1337.

We can run the application using node app.js. Alternatively, let's add a start script to package.json so that we can use the npm start command, following the usual practice.

{
    "name": "contacts",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "start": "node app.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "type": "commonjs",
    "dependencies": {
        "sails": "1.5.18"
    }
}

Let's run the start command and wait for the ship to appear in the terminal! Then, open http://localhost:1337 in your browser.

npm start

... some debug logs ...
info:
info:                .-..-.
info:
info:    Sails              <|    .-..-.
info:    v1.5.18             |\
info:                       /|.\
info:                      / || \
info:                    ,'  |'  \
info:                 .-'.-==|/_--'
info:                 `--'-------'
info:    __---___--___---___--___---___--___
info:  ____---___--___---___--___---___--___-__
info:
info: Server lifted in `D:\Playground\contacts`
info: To shut down Sails, press <CTRL> + C at any time.
info: Read more at https://sailsjs.com/support.

Ah! We get a 404 - Not Found error in the browser. That's expected because we haven't written any code to handle the root route yet.

I wish Sails would render something similar to Sinatra's welcome page, with a code snippet that we could copy and paste to get started. It would make for a more guided learning experience. Next.js also offers a guided experience through its console messages.

Nice! :)


Let's fix the 404 - Not Found error. First, we need to define the root route. In Sails, routes are defined in the config/routes.js file. We don't have a config folder or a routes.js file yet, so let's create both.

mkdir config
touch config/routes.js

Open routes.js and add the following code.

module.exports.routes = {
  "GET /": "HomeController.index",
};

Eventually, we'll have many more files in the config folder.

When defining exports in the config folder, don't just write module.exports. Use module.exports.[filename] instead, such as module.exports.routes for routes.js or module.exports.globals for globals.js.

routes is an object whose keys consist of an HTTP verb, a space, and a path. The corresponding values specify a controller and a function within that controller. When a user visits the given route, the specified controller function is executed.

In Sails, controllers are located in the api/controllers folder. We don't have the api or controllers folders, or a HomeController.js file yet. Let's create them.

mkdir api
mkdir api/controllers
touch api/controllers/HomeController.js

Open HomeController.js and add the following code.

module.exports = {
    index: (req, res, next) => {
        res.send("hello, world");
    },
};

If you're familiar with Express, this code should look familiar to you! And it is. Sails uses Express internally for its core web functionalities.

We now have a root route and the code to handle it. With these changes in place, we're ready to run the app again. We should see the hello, world text when we visit the root route.


Waterline is the database ORM built by the same team that built the Sails framework. As a result, Waterline integrates seamlessly with Sails.

Waterline supports several databases, including MySQL, PostgreSQL, and MongoDB, through adapters. For example, the sails-disk package provides a disk-based adapter. I'll use this adapter for our sandbox demos.

You know what? I'll use the sails-hook-orm package instead, as it includes the sails-disk adapter and other useful components. This way, I won't have to write any configuration code.

npm i -E sails-hook-orm

We should have a contacts table in the database. To work with this table, we need to create a Contact model. In Sails, models are located in the api/models folder. We don't have the models folder or a Contact.js file yet, so let's create them.

mkdir api/models
touch api/models/Contact.js

Open Contact.js and add the following code.

module.exports = {
    tableName: "contacts",

    attributes: {
        id: {
            type: "number",
            autoIncrement: true,
        },
        firstName: {
            type: "string",
            required: true,
        },
        lastName: {
            type: "string",
        },
    },
};

The code is self-explanatory. We're creating a contacts table with three columns: id, firstName, and lastName, each with the given attributes. For now, don't worry about these attributes or their values.

A Sails application can run without model and database support. However, if we want to use models and databases, we need to explicitly tell Sails that we're going to use models in our app. To do that, we need to set the models option to true in the global options.

The global options are defined in the config/globals.js file. We don't have this file yet, so let's create it.

touch config/globals.js

Open globals.js and add the following code.

module.exports.globals = {
    models: true,
};

In theory, this should work. However, due to some awkwardness in the internal configuration, you'll encounter a bunch of errors if you try to run the app. For example, you may need to set _ (Lodash) and async to false, while keeping sails set to true, and so on.

To save you the trouble of troubleshooting these issues, let's add a few more configuration options to globals.js.

module.exports.globals = {
    models: true,
    _: false,
    async: false,
    sails: true
};

Now, if you run the app, it should no longer throw any errors. Go ahead and run it. You should see the following text in the console.

Excuse my interruption, but it looks like this app
does not have a "migrate" setting configured yet.
(perhaps this is the first time you're lifting it with models?)

Tired of seeing this prompt?  Edit config/models.js.

In a production environment (NODE_ENV=production) Sails always uses
migrate:'safe' to protect against inadvertent deletion of your data.
But during development, you have a few different options:

1. FOR DEV:      alter   wipe/drop and try to re-insert ALL my data (recommended)
2. FOR TESTS:    drop    wipe/drop ALL my data every time I lift Sails
3. FOR STAGING:  safe    don't auto-migrate my data. I will do it myself

Read more: sailsjs.com/docs/concepts/models-and-orm/model-settings#?migrate
--------------------------------------------------------------------------------

What would you like Sails to do this time?
 ** NEVER CHOOSE "alter" or "drop" IF YOU ARE WORKING WITH PRODUCTION DATA **

prompt: ?:

Sails is now waiting for us to choose a migration strategy. The available options are 1, 2, and 3, and their meanings are explained in the console output. For now, let's enter 1 and press Enter to continue running the app. But, the problem is that Sails will ask us this question every time we start the app. To avoid this, we need to specify our choice in a configuration file. The file we need is config/models.js. We don't have this file yet, so let's create it.

touch config/models.js

Open models.js and add the following code.

module.exports.models = {
    migrate: "alter",
};

With the configuration saved in config/models.js, Sails won't ask us the same question again! Run the application once more, and you should see the following message somewhere in the console output.

info: ·• Auto-migrating...  (alter)
info:    Hold tight, this could take a moment.
info:  ✓ Auto-migration complete.

Perfect! The contacts table has been created in the database, and we're ready to perform CRUD operations on it using the Contact model. For example, open HomeController.js and add the following lines inside the index function.

module.exports = {
    index: async (req, res, next) => {
        const contacts = await Contact.find();
        console.log("contacts:", contacts);

        res.send("hello, world");
    }
};

I've converted the function into an `async` function and then called the `Contact.find()` method. Re-run the application, and you should see the following output:

contacts: []

This means our database is configured correctly.

One last point before we move on to views: we now have .tmp/localDiskdb/contacts.db (and archive.db) files because we've chosen to use the disk-based database adapter.


Instead of returning plain hello, world text, let's render it as an h1 heading. To do this, we need to create a folder named views and add an EJS template file inside it. For example, we can use home.ejs for the root route. We don't have the views folder or the home.ejs file yet, so let's create both.

mkdir views
touch vies/home.ejs

Open home.ejs and add the following code.

<h1>hello, world</h1>

Next, let's update the index function in HomeController.js to render this template instead of sending plain hello, world text.

module.exports = {
    index: async (req, res, next) => {
        const contacts = await Contact.find();
        console.log("contacts:", contacts);

        res.render("home");
    }
};

Re-run the app! You should now see hello, world displayed as a heading.

I think we should stop here for Chapter 01, as we've covered the basics of the MVC concepts in Sails. I'd like to highlight that Sails provides MVC functionality out of the box with just a few lines of code and some uncommon adjustments. Once we get past these initial hurdles, we have a nice framework to work with!