A simple text highlighting component with React

In this post, we would create a simple React component which would allow a user to highlight selected text using a mouse. Also, it would also allow an optional callback function, which will receive the selection details.

Research on existing solutions

It’s always a good idea to search for existing well-tested components which may meet our requirements. After some quick search, all similar existing solutions seem to fall into the following categories:

  1. They accept text to be searched as props thus acting more like search/replace utilities, not allowing dynamic selection using mouse.
  2. They are part of bigger and complicated component libraries thus needlessly increasing dependencies.
    We don’t want both. So let’s create our own solution.

Ironing out the requirements

Our component will support the following props (inputs to the component):

  • text: Text to be shown to the user
  • selectionHandler (optional): A callback function. It will receive an object containing following details about selection.
    • selected text
    • selection start index
    • selection end index
  • customClass (optional): A user-provided CSS class to style the selected text

Component Code

import React, { Component } from 'react';
import PropTypes from 'prop-types';

const propTypes = {
    text: PropTypes.string.isRequired,
    customClass: PropTypes.string,
    selectionHandler: PropTypes.func
};

/**
 * Highlighter component.
 * 
 * Allows highlighting of the text selected by mouse with given custom class (or default)
 * and calls optional callback function with the following selection details:
 * - selected text
 * - selection start index 
 * - selection end index
 */
export default class HighLighter extends Component {
    constructor(props) {
        super(props);
        this.state = {
            text: props.text,
            isDirty: false,
            selection: '',
            anchorNode: '?',
            focusNode: '?',
            selectionStart: '?',
            selectionEnd: '?',
            first: '',
            middle: '',
            last: ''
        };
        this.onMouseUpHandler = this.onMouseUpHandler.bind(this);
    }

    onMouseUpHandler(e) {
        e.preventDefault();
        const selectionObj = (window.getSelection && window.getSelection());
        const selection = selectionObj.toString();
        const anchorNode = selectionObj.anchorNode;
        const focusNode = selectionObj.focusNode;
        const anchorOffset = selectionObj.anchorOffset;
        const focusOffset = selectionObj.focusOffset;
        const position = anchorNode.compareDocumentPosition(focusNode);
        let forward = false;

        if (position === anchorNode.DOCUMENT_POSITION_FOLLOWING) {
            forward = true;
        } else if (position === 0) {
            forward = (focusOffset - anchorOffset) > 0;
        }

        let selectionStart = forward ? anchorOffset : focusOffset;

        if (forward) {
            if (anchorNode.parentNode.getAttribute('data-order')
                && anchorNode.parentNode.getAttribute('data-order') === 'middle') {
                selectionStart += this.state.selectionStart;
            }
            if (anchorNode.parentNode.getAttribute('data-order')
                && anchorNode.parentNode.getAttribute('data-order') === 'last') {
                selectionStart += this.state.selectionEnd;
            }
        } else {
            if (focusNode.parentNode.getAttribute('data-order')
                && focusNode.parentNode.getAttribute('data-order') === 'middle') {
                selectionStart += this.state.selectionStart;
            }
            if (focusNode.parentNode.getAttribute('data-order')
                && focusNode.parentNode.getAttribute('data-order') === 'last') {
                selectionStart += this.state.selectionEnd;
            }
        }

        const selectionEnd = selectionStart + selection.length;
        const first = this.state.text.slice(0, selectionStart);
        const middle = this.state.text.slice(selectionStart, selectionEnd);
        const last = this.state.text.slice(selectionEnd);

        this.setState({
            selection,
            anchorNode,
            focusNode,
            selectionStart,
            selectionEnd,
            first,
            middle,
            last
        });

        if (this.props.selectionHandler) {
            this.props.selectionHandler({
                selection,
                selectionStart,
                selectionEnd
            });
        }

    }

    render() {
        if (!this.state.selection) {
            return (
                <span
                    onMouseUp={this.onMouseUpHandler}>{this.state.text}
                </span>
            )
        } else {
            return (
                <span
                    onMouseUp={this.onMouseUpHandler}>
                    <span
                        data-order="first" >
                        {this.state.first}
                    </span>
                    <span
                        data-order="middle"
                        className={this.props.customClass || "default"}>
                        {this.state.middle}
                    </span>
                    <span
                        data-order="last">
                        {this.state.last}
                    </span>
                </span>
            )
        }

    }
}

HighLighter.propTypes = propTypes;

Component Logic

Our challenge here is to get the text which got selected when the user selects a certain portion with the mouse. We use DOM’s window.getSelectionAPI for this. This API is called in the mouseup event. It returns a Selection object with many useful attributes and methods for our selection. The ones which are useful to us are:

  • anchorNode Node in which the selection begins.
  • anchorOffset A number representing the offset of the selection’s anchor within the anchorNode.
  • focusNode The Node in which the selection ends.
  • focusOffset A number representing the offset of the selection’s anchor within the focusNode.
  • toString() The selected text.

The anchor node and anchor offset give us the distance of start of the selection in terms of character. The end of the selection can be determined by adding the length of selection itself (given by toString method on the Selection object). These start and end point are then used to split our original text into three separate spans identified by unique data-attributes:

  • first text before the selection
  • middle selection text (style applied to this span to highlight it)
  • last text after selection

All these key info including endpoints, offsets, nodes, and text portions are kept in the components state. If an optional callback is provided, we call it with an object argument containing selection text and endpoints.

Although quite simpler on the surface, there are following hidden complexities in this selection logic:

  1. After the initial selection, new span nodes get introduced (to mark the highlighted text using CSS styling). These changes introduce new anchorNode/focusNode for each span along with relative offsets. For any further selections, we may then have to do relative adjustments depending on which span we started from using the earlier selection endpoints.
  2. Users might do the selection in reverse order. We then have to do our calculations with response to focusNode/focusOffset (shown in previous snippets). We use DOM’s compareDocumentPosition API (which gives us relative position nodes) along with the difference in the offsets to determine the direction of selection.

Note

There are few alternate ways to do the highlight, including Range.surroundContents API. However, these directly modify the DOM which is discouraged in React. We want to have as limited direct interaction with DOM as possible.

You can find the complete source code here, NPM package here and test it live here.

An Easy and Fun Guide to Redux – Intro and Immutability

Hi!

I must admit that I am quite late to the party, but I am quite enjoying my journey in React/Redux universe. One thing, however, always bugs me: most of the online tutorials about React/Redux are seems like a tour de force of all the packages, tools and concepts in the React/Redux ecosystem. Although, I sincerely respect and admire the effort they put into these but such an approach doesn’t suit me well. I believe people learn in different ways. Some prefer the whole picture approach, while others piecemeal. This guide takes the second approach. In each chapter, we build a layer of concepts, focusing on a single framework/tools or particular functionalities of it, building the foundation for the next. Also, I intend to do it in most unofficial, fun way loaded with practical examples.

In this chapter, we would be just covering the basic introduction of Redux and in-length discussion of Immutability. We will end with bare essential setup required for redux. Other than that, there won’t be any code specific to redux in this chapter. We will do that from the next chapter.

So what’s Redux?

From the landing page of redux.js.org : 


A predictable state container for JavaScript apps. 

Let’s decipher it.
A state is simply an object containing your app’s data in one place. The container is the storage where this state is kept. For those familiar with RDBMS like MySQL, container loosely equals database and state the data in it (say a row in the table). However, there is a unique restriction: State must be immutable. In our RDBMS analogy, it’s somewhat like creating a new row for each change rather than editing an existing one. Let’s detour a little to understand the concept of Immutability further.

So what’s Immutability?

Rather than bore you with exact definitions, let me explain it with the following set of examples:

Chess Vignette
Imagine if you are punished to record a boring chess game. You have two options:

  • note each move (e.g. King e1-e4)
  • take a snap of the board after every move like a lazy, spoiled brat

Of course, all of you whose childhood was disciplined by the economy of resources would go for the first option.

But you are now dealt with another punishment. After the completion of the game, you may be required to set up the board to any particular move in the game. Now, which approach of recording game do you think would have made life easier for you?

For the responsible first approach, you will have to start from an initial board each time and executing all the moves till the required one (or do some clever relative slicing of moves]. For the irresponsible second approach, you could just take out the snap of given move and set up the board immediately. It pays to be a spoiled brat sometimes.

The first approach here mutates the existing state of the board on each move, whereas the second approach gives us an immutable snapshot at every move. The immutable approach, although being more wasteful of resources, provides us with following cool benefits :

  • The capability of easily rolling back to any point in time. This is what predictability meant earlier. We can reproduce any state (for any move) at will with surety.
  • Ease of maintenance and reducing the risk of errors. There might be a possibility we record one of the moves wrong. This might cause confusion for all further set of moves. We might need separate book-keeping to add additional surety. (Most modern systems use special audit tables for this purpose, which normally keep both new and old records for each possible change, and are themselves immutable (changing existing audit record is a big NO)).

Coming back to JavaScript, let’s go through an example. Let’s say you have the following array of users, with each item containing the user’s name, email, and age. You later realized that you had entered the wrong age for the user John Galt. If mutations are allowed, you would change the age directly on the original object. In the immutable approach, you would rather return a fresh copy of users. You now need to send an apology email to this user. Thus, you need to identify him first. Below, we show the code samples for both the scenarios.

Mutable Version

let users = [
    {
        name: {
            first: 'John',
            last: 'Galt'
        },
        email: 'john.galt@whois.com',
        age: 30
    },
    {
        name: {
            first: 'Mickey',
            last: 'Mouse'
        },
        email: 'mickey.mouse@didney.com',
        age: 90
    },
    {
        name: {
            first: 'Charlie',
            last: 'Chaplin'
        },
        email: 'charlie.chaplin@hollywood.com',
        age: 129
    },
];

const ChangeUserFirstName = 'John',
    ChangeUserLastName = 'Galt',
    ChangeAge = 38;

// Following change spoils the existing object for everyone. Other users won't 
// have any way of knowing the original state.
users.forEach(user => {
    if (user.name.first === ChangeUserFirstName &&
        user.name.last === ChangeUserLastName) {
        user.age = 38;
    }
});

console.log('users', users);

// Find the changed record.
const changedRecord = users.filter(user => (user.name.first === ChangeUserFirstName &&
    user.name.last === ChangeUserLastName));
console.log('changedRecord', changedRecord);
// No way to retrieve original record now :(
// const originalRecord = users.filter(user=>user.name.first === ChangeUserFirstName &&
//         user.name.last === ChangeUserLastName);
// console.log('originalRecord', originalRecord);
// returns same record as changedRecord
users [ { name: { first: 'John', last: 'Galt' },
email: 'john.galt@whois.com',
age: 38 },
{ name: { first: 'Mickey', last: 'Mouse' },
email: 'mickey.mouse@didney.com',
age: 90 },
{ name: { first: 'Charlie', last: 'Chaplin' },
email: 'charlie.chaplin@hollywood.com',
age: 129 } ]
changedRecord [ { name: { first: 'John', last: 'Galt' },
email: 'john.galt@whois.com',
age: 38 } ]

Immutable Version

let users = [
    {
        name: {
            first: 'John',
            last: 'Galt'
        },
        email: 'john.galt@whois.com',
        age: 30
    },
    {
        name: {
            first: 'Mickey',
            last: 'Mouse'
        },
        email: 'mickey.mouse@didney.com',
        age: 90
    },
    {
        name: {
            first: 'Charlie',
            last: 'Chaplin'
        },
        email: 'charlie.chaplin@hollywood.com',
        age: 129
    },
];

const ChangeUserFirstName = 'John',
    ChangeUserLastName = 'Galt',
    ChangeAge = 38;

let CurrentDayOfBirth = null;

// Following change spoils the existing object for everyone. Other users won't 
// have any way of knowing the original state.
const freshUsers = users.map(user => {
    if (user.name.first === ChangeUserFirstName &&
        user.name.last === ChangeUserLastName) {
        // Create a fresh user record. All the key from both the existing object
        // are copied in the empty object follwed by overwriting from incoming changes.
        return Object.assign({}, user, { age: ChangeAge });
    }
    // Unmodified records.
    return user;
});

console.log('users', users);
console.log('freshUsers', freshUsers);

// Find the changed record.
const changedRecord = freshUsers.filter(user => !users.includes(user));
const originalRecord = users.filter(user => user.name.first === ChangeUserFirstName &&
    user.name.last === ChangeUserLastName);
console.log('changedRecord', changedRecord);
console.log('originalRecord', originalRecord);
users [ { name: { first: 'John', last: 'Galt' },
email: 'john.galt@whois.com',
age: 30 },
{ name: { first: 'Mickey', last: 'Mouse' },
email: 'mickey.mouse@didney.com',
age: 90 },
{ name: { first: 'Charlie', last: 'Chaplin' },
email: 'charlie.chaplin@hollywood.com',
age: 129 } ]
freshUsers [ { name: { first: 'John', last: 'Galt' },
email: 'john.galt@whois.com',
age: 38 },
{ name: { first: 'Mickey', last: 'Mouse' },
email: 'mickey.mouse@didney.com',
age: 90 },
{ name: { first: 'Charlie', last: 'Chaplin' },
email: 'charlie.chaplin@hollywood.com',
age: 129 } ]
changedRecord [ { name: { first: 'John', last: 'Galt' },
email: 'john.galt@whois.com',
age: 38 } ]
originalRecord [ { name: { first: 'John', last: 'Galt' },
email: 'john.galt@whois.com',
age: 30 } ]

Clearly, we see some immediate benefits for the second approach:

  • Original records have not tampered. So let’s say if John Galt disapproves of our change, we can immediately roll back to his original record.
  • Identifying the record which changed is super easy. This is because we now need to just check for object reference rather than delving deeper in it.

I hope these examples would have made the basics of Immutability quite clear, especially its benefits. Also, we now a better understanding of each of the cryptic terms in the terse definition of Redux and it’s the relationship with Immutability.

Bare-Bone Redux setup

I will now end this chapter with the basic setup required for our future Redux experiments.

Few key points about the setup:

  • We would focus only on the very basics of redux here. We won’t be dealing with any starter-kits, non-essential tools like Webpack or other libraries like React except some bare essential.
  • I believe you have Node/NPM already set up on your system and are familiar with common ES6 features. If not, don’t worry. Following links will get you started:

As promised, I won’t be adding loads of dependencies or tools. Only extra packages required would be those needed for babel-node. babel-node is quite similar to the node, except that it supports all missing ES6 features in node including ES6 imports. You can even avoid this and just install the redux package. You may need to do a minor modification to code samples to use Node’s CommonJS module. Just run following commands:

cd app
npm init
npm install --save-dev @babel/core @babel/node @babel/preset-env
npx babel-node index.js --presets=@babel/preset-env

Or you can pull this repository and just do

cd medium-redux
npm install

Next Chapter: Actions, Store, Reducers, and Pure Functions

Please share your valuable comments, suggestion or criticism in response, or applaud/share if you liked the article. You can also follow me for updates on future chapters.

Happy Hacking!

Implementing Publisher-Subscriber Pattern Using JavaScript, NodeJS and WebSockets

Recently I ticked off an item from my bucket list:
Do a quick and dirty implementation of the Publisher-Subscriber pattern.

For the uninitiated, Publisher-Subscriber pattern is a quite common messaging pattern. Following is a brief explanation of this pattern in very plain language. You can find a more detailed explanation including various possible implementation here.

In the Publisher-Subscriber pattern, publishers publish messages without bothering about who receives it. Similarly, the subscribers can be blissfully unaware of publishers, just consuming messages from topics of interest to them. This pattern is quite commonly confused with other similar patterns like a message queue and observer pattern. However, in both of these, publisher (or producer) is aware of the subscriber (or consumers). 

Decoupling

This decoupling of the publishers and subscribers is achieved by introducing an intermediary, also known as a broker. Publishers publish the message to this broker, typically under a certain topic. Subscribers can subscribe to specific categories on this broker. Whenever a new message arrives under a certain topic, broker delivers them to subscribers subscribed to that topic.

A real-life example of Publisher-Subscriber pattern would be cable television. Different media companies create content and dump them on their respective channels. Viewers then consume content from the channels of interests to them, say sports or movies channel. Cable services here act as the broker.

Now, let’s get our hand dirty by implementing this pattern using NodeJS and client-side JavaScript. We would need a few extra packages too to get the ball rolling:

  • ws – A robust but simple implementation of WebSocket Server/Client for NodeJS
  • express – To serve static HTML content (publishers, subscribers)

Don’t be worried if you came across WebSockets for the first time or have never used them. WebSockets is a communication protocol, which allows two-way communication between server and client (browser in our case), as opposed to one-way protocols like HTTP. In our case, WebSockets allows us to both send messages from server to browser (subscribers) and from browser to the server (publishers). There are other ways and supporting protocols for doing this two-way communication, like long polling using Comet or Bayeux protocols, but none of them is as simple and straight-forward as WebSockets.

const WebSocketServer = require('ws').Server;
const express = require('express');
const path = require('path');
const server = require('http').createServer();
const PubSubManager = require('./pubsub');

const app = express();
const pubSubManager = new PubSubManager();

app.use(express.static(path.join(__dirname, '/public')));
const wss = new WebSocketServer({ server: server });
wss.on('connection', (ws, req) => {
    console.log(`Connection request from: ${req.connection.remoteAddress}`);
    ws.on('message', (data) => {
        console.log('data: ' + data);
        const json = JSON.parse(data);
        const request = json.request;
        const message = json.message;
        const channel = json.channel;

        switch (request) {
            case 'PUBLISH':
                pubSubManager.publish(ws, channel, message);
                break;
            case 'SUBSCRIBE':
                pubSubManager.subscribe(ws, channel);
                break;
        }
    });
    ws.on('close', () => {
        console.log('Stopping client connection.');
    });
});

server.on('request', app);
server.listen(8080, () => {
    console.log('Server listening on http://localhost:8080');
});

We first prepare the our WebSocket server using  ws. It provides multiple ways of creating WebSocket server. The approach which we use here is running it over an existing NodeJS server. We also run an Express app on the same server. As WebSockets are designed to work over HTTP ports and support HTTP proxies, we exploit it to our advantage by the same endpoint for both our WebSocket server and Express app. All normal HTTP requests are forwarded to Express app, which currently serves only the static content: static HTML files containing code for publisher and subscriber. All WebSocket specific requests are transferred over to our WebSocket server.
The server can receives data from the client on successful connection and respond back. It differentiates between the publishers and subscribers on the basis of a key provided in the incoming data (request).

class PubSubManager {
    constructor() {
        this.channels = {
            weather: {
                message: '',
                subscribers: []
            },
            sports: {
                message: '',
                subscribers: []
            }
        }
        this.brokerId = setInterval(() => { this.broker() }, 1000);
    }
    subscribe(subscriber, channel) {
        console.log(`subscribing to ${channel}`);
        this.channels[channel].subscribers.push(subscriber);
    }

    removeBroker() {
        clearInterval(this.brokerId);
    }

    publish(publisher, channel, message) {
        this.channels[channel].message = message;
    }

    broker() {
        for (const channel in this.channels) {
            if (this.channels.hasOwnProperty(channel)) {
                const channelObj = this.channels[channel];
                if (channelObj.message) {
                    console.log(`found message: ${channelObj.message} in ${channel}`);

                    channelObj.subscribers.forEach(subscriber => {
                        subscriber.send(JSON.stringify({
                            message: channelObj.message
                        }));
                    });
                    
                    channelObj.message = '';
                }
            }
        }
    }
}
module.exports = PubSubManager;

The Publisher-Subscriber pattern is implemented here using the PubSubManager class. This class provides APIs to publish a message to certain channel (topic), add subscribers to certain channel, a data structure to hold the channels and its messages and subscribers and finally a broker which continuously polls (naively using setInterval) this data structure for any new message. If any new message is published to any channel, it’s delivered by the broker on the following poll to this channel’s subscribers and removed immediately from the store.

<!DOCTYPE html>
<html>

<head>
    <style>
        body {
            font-family: Tahoma, Geneva, sans-serif;
        }

        div {
            display: inline;
        }
    </style>
    <script>
        function publish() {
            var message = document.getElementById('message').value;
            var channel = document.getElementById('channel').value;

            var host = window.document.location.host.replace(/:.*/, '');
            var ws = new WebSocket('ws://' + host + ':8080');
            ws.onopen = function () {
                ws.send(JSON.stringify({
                    request: 'PUBLISH',
                    message: message,
                    channel: channel
                }));
                ws.close();
            };
        }
    </script>
</head>

<body>
    <h1>Publisher</h1>
    <input type="text" id="channel" placeholder="Channel (weather, sports etc.)" />
    <input type="text" id="message" placeholder="What you want to publish?" />
    <button onclick="publish()">Publish</button>
</body>

</html>

In our implementation, the publisher is provided by pub.html, served statically by express. It can publish message under any channel (currently limited to weather and sports). To do so, it creates a connection with our WebSocket server, sends the channel, message and a request key to identify itself as publisher. It then immediately closes the connection. The server, on the other hand, parses this data and publishes the message under relevant topic through PubSubManager’s publish method.

<!DOCTYPE html>
<html>

<head>
    <style>
        body {
            font-family: Tahoma, Geneva, sans-serif;
        }

        div {
            display: inline;
        }
    </style>
    <script>
        function subscribe() {
            var message = document.getElementById('message');
            var channel = document.getElementById('channel').value;
            var host = window.document.location.host.replace(/:.*/, '');
            var ws = new WebSocket('ws://' + host + ':8080');
            ws.onopen = function () {
                ws.send(JSON.stringify({
                    request: 'SUBSCRIBE',
                    message: '',
                    channel: channel
                }));
                ws.onmessage = function(event){
                    data = JSON.parse(event.data);
                    message.innerHTML = data.message;
                };
            };
        }
    </script>
</head>

<body>
    <h1>Subscriber</h1>
    <input type="text" id="channel" placeholder="Channel (weather, sports etc.)" />
    <button onclick="subscribe()">Subscribe</button>
    <div>
        <h1>Message:</h1>
        <div id="message"></div>
    </div>
</body>

</html>

The subscriber implementation, provided by sub.html, works quite similarly to pub.html except the following differences:

  • No message is sent to the server, only the channel of interest. The server subscribes it to the relevant channel using the subscribe method of PubSubManager.
  • The connection with the server is kept indefinitely active, to allow any incoming update from the WebServer. The subscription happens through the subscribe method of PubSubManager by the server.

You can get the complete demo app here. Following are the steps to run the demo:

  • Go to app folder and get the server running:
    • cd pubsub
    • npm install
    • node index.js
  • By default the server runs on http://localhost:8080.
  • Open the subscriber at http://localhost:8080/sub.html. Input channel to subscribe to (say weather). Click Subscribe.
  • Open the publisher at http://localhost:8080/pub.html. Input channel (say weather) and message ( say Cloudy with brief showers). Press Publish.
  • The subscriber receives message under Message heading.
  • You can run multiple publishers and subscribers over different channels (currently limited to weather and sports).

There are many improvements possible in this demo implementation, right from a securing WebSocket server to persisting message queue. However, the goal here was to create a quick and working implementation. Please feel free to improve and build upon it. For those who love challenges, I would suggest implementing own WebSocket server using NodeJS (Next item on my bucket list 😉 ). You can get started with this MDN link and this RFC. 

Related useful links:

Power of reduce – Swiss army knife of functional JavaScript

Today, we will see a powerful use of reduce function provided by JavaScript. In this example, we are provided with a mixed array of numbers, string, and objects. What we wish to achieve is a summary output array containing only three members:

  • sum of numbers in the input array
  • single string containing all strings in input array concatenated with space
  • single object containing all the object members (key-value pairs) of objects in the input array

The reduce function here makes use of ‘typeof’ and ternary operators to do the right operations (could be possibly replaced by individual filters).

 

let input = [
  1,
  2,
  3,
  { a: 'Apple', b: 'Bag' },
  5,
  6,
  'hello',
  { 1: 'One', 2: 'Two' },
  'world'
];
//op = [sum of number, string concatenated with space, single object with all keys]
let op = [0, '', {}];
op = input.reduce((prev, curr) => {
  typeof curr === 'number'
    ? (prev[0] = prev[0] + curr)
    : typeof curr === 'string'
      ? (prev[1] = prev[1] + ' ' + curr)
      : (prev[2] = { ...prev[2], ...curr });
  return prev;
}, op);
console.log(op);
//[ 17,
//  ' hello world',
//  { '1': 'One', '2': 'Two', a: 'Apple', b: 'Bag' } ]

 

fun with functions in javascript

I always had a love-hate kind of relationship with JavaScript. Like most other Software Engineers out there, my base of programming is rooted in Structural and Object Oriented Programming.

I was born in it, moulded by it.

I was very much delighted when the latest ES versions sugar coated Javascript’s prototypal inheritance with the familiar classes. I always ignored the raw powers inherited by functions being a first class citizen in JavaScript. Then, I came across functional programming. Things changed.

I scoured various online blogs and tutorials about this new buzzword (apparently it’s older than me, mathematically speaking :P). They ranged from pure academical rhetoric to the practical applications. One that stood out for me was a YouTube channel which gave a very oddball, crazy, entertaining but crystal clear explanation of functional programming (in JavaScript).

Thanks @mpj, for such an awesome channel!

Other than it, few good reads suggested on multiple places:

Will be posting some of my experiments with the functional programming soon.
Happy coding!