Thursday, May 17, 2018

How to create and register a React redux middleware?

Overview


This post is just a reminder how to create and register a custom redux middleware.

Redux middleware: definition.

The middleware class

const middleware = function f1(store) { 

    return function f2(next) {
        
        return function f3(action) {
        
            // Do nothing but trace the action 
            console.log(`MIDDLEWARE> action:${JSON.stringify(action)}`)
            return next(action);
        } 
    }
}

export default middleware ;

The store creation and middleware registration

import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunkMiddleware  from 'redux-thunk';

import counterReducer   from './counter/counterReducer';

import middleware   from './middleware';

const rootReducer = combineReducers({
    counter : counterReducer,
});

const appliedMiddleware = applyMiddleware(thunkMiddleware, middleware);
const store             = createStore(rootReducer, {}, appliedMiddleware);

store.subscribe(function() {
    //console.log('STORE SUBSCRIBED ');
} );

export default store;

Friday, May 4, 2018

Redux Workflow - Summary

Overview


A blog post to gather my understanding of Redux (redux.js.org/).
Another good explanation can be found at Redux explained.

On button click calling synchronous action

  • The ButtonClickAction() method is called by the onClick attribute of a button and return the action:
    { type :‘BUTTON_CLICK_ACTION’ }
  • Because the action return an object it is automatically dispatched.
  • The dispatching trigger all registered reducers to be called.
  • The dispatching trigger all registered mapStateToProps() to be called. The global state is pass to each mapStateToProps() call. mapStateToProps() return the list of props for its component.
    • If the call return a different result from the previous call, a call to Component.render() will be executed

Summary

  • OnClick
  • Action get dispatched
  • Reducers
  • mapStateToProps
  • Component.render() if needed


On button click calling an asynchronous action

  • Asynchronous action are typically an HTTP call.
  • The Asynchronous action must be a function returning a return function(dispatch) {};
  • The internal function must dispatch 2 synchronous actions, for example requestStartedAction() at first and requestReceivedAction(data) when the data is received, as described below.

//
export function fetchAction(city) {

    return function(dispatch) {

        dispatch(requestStartedAction());

        axios.get(url, config).then(function(data) { 

            dispatch(requestReceivedAction(data));
        });
    }
}

Wednesday, March 7, 2018

Parentheses Expression Parser

Overview 


A simple coding exercise, parsing parentheses expressions
  • Given a string containing the characters '(', ')', '{', '}', '[' and ']' and any other characters in between determine if the parentheses are balanced.
using mocha+chai test framework.

Valid Expressions

 - "()"
 - "(){}[]"
 - "([ok])"
 - "{([ok])}"
 - "function() { return (1+1); }"

Invalid Expressions

 - "(]"
 - "([)]"
 - "([ok]})"
 - "{([ok])})"

Github Repo: ParenthesesParser

Source Code

let Stack = require('./Stack');
let print = console.log;

function ParenthesesParser(expression) {

    this._parentheseDefinition = {
        '(' : ')', 
        '{' : '}', 
        '[' : ']',
    };
    this.parse = function(expression) {

        if(!expression)
            throw new Error(ParenthesesParser.EXPRESSION_CANNOT_BE_NULL_OR_UNDEFINED);

        let stack = new Stack();

        for(let i = 0; i < expression.length; i++) {
            let c = expression.charAt(i);
            if(this.isOpenParenthese(c)) {
                stack.push(c);
            }
            else {
                if(this.isCloseParenthese(c)) {
                    let p = stack.pop();
                    if(c !== this._parentheseDefinition[p]) // Fail
                        return this.createResult(false, `position:${i}, expected:${this._parentheseDefinition[p]}, found:${c}`);
                }
            }
        }
        // if stack is empty the expression is valid else we have an invalid expression
        // with a missing closing parenthese like this '(ok'
        const passed = stack.isEmpty();
        return this.createResult(passed, passed ? `` : `expected:"${this._parentheseDefinition[stack.pop()]}" at end of expression`);
    }
    this.createResult = function (passed, errorMsg) {
        return {
            Expression   : this._expression,
            Passed       : passed,
            ErrorMessage : ParenthesesParser.PARSING_ERROR + " " + errorMsg
        };
    }
    this.isOpenParenthese = function(c) {

        return c in this._parentheseDefinition;
    }
    this.isCloseParenthese = function(c) {
        
        return Object.values(this._parentheseDefinition).indexOf(c) !== -1;
    }
};

ParenthesesParser.EXPRESSION_CANNOT_BE_NULL_OR_UNDEFINED = "expression cannot be null or undefined";
ParenthesesParser.PARSING_ERROR                          = "Parsing Error";

module.exports = ParenthesesParser;


Unit tests


let assert = require('chai').assert;
let expect = require('chai').expect;
let ParenthesesParser = require('../src/ParenthesesParser');
let print = console.log;

describe('ParenthesesParser', () => {

    let subject;

    before(() => {
        subject = new ParenthesesParser();
    });
    
    describe('Valid expressions', () => {

        let validExpressions = [
            "()" ,"(a)", "((((()))))", 
            "((((([[[]]])))))",  "((((([[[{{{}}}]]])))))",  "((((([[[{{{a}}}]]])))))", 
            "function(abs(compute(run(exec(array[list[array[object{object{object[1]}}]]])))))", 
            "(){}[]" , "(()){{}}[[]]" ,
            "([ok])" ,
            "{([ok])}" ,
            "function() { return (1+1); }" ,
            "<(>)", // This one passed because '<' and '>' are not considered Parentheses
            "(\\)", "(\\//)", "(\")",
            "Valid-Expression", "(Valid-Expression)"
        ];
        it(`should return passed on expression '${validExpressions}'`, () => {

            validExpressions.forEach((exp) =>{
                expect(subject.parse(exp).Passed).to.be.true;
            });
        });
    });

    describe('Invalid expressions', () => {
       
        let invalidExpressions = [
            "(invalid-expression", "invalid-expression)",
            "(" , "((((())))", , "(((((])))))", 
            "[", "{",
            "(){[]" ,
            "([ok)" ,
            "{([ok]}" ,
            "function() { return (1+1; }" ,
        ];
        it(`should return failed on expression '${invalidExpressions}'`, () => {

            invalidExpressions.forEach((exp) =>{
                expect(subject.parse(exp).Passed).to.be.false;
            });
        });
        it(`should return specific error message on failure`, () => {

            let exp = "[(a])";
            let expected = "Parsing Error position:3, expected:), found:]";
            let result = subject.parse(exp);
            expect(result.ErrorMessage).to.equal(expected);
            expect(result.ErrorMessage.startsWith(ParenthesesParser.PARSING_ERROR)).to.be.true;
        });
        it(`should return specific error message on failure, complex expression`, () => {

            let exp = "((((([[[{{{a)}}}]]])))))";
            let expected = "Parsing Error position:12, expected:}, found:)";
            let result = subject.parse(exp);
            expect(result.ErrorMessage).to.equal(expected);
        });
    });

    describe('Invalid expressions, missing closing parenthese', () => {

        it(`should return specific error message on failure on '(ok'`, () => {

            let exp = "(ok";
            let expected = 'Parsing Error expected:")" at end of expression';
            let result = subject.parse(exp);
            expect(result.ErrorMessage).to.equal(expected);
        });

        let invalidExpressionsMissingClosingParentheses = [
            "(ok", "{ok", "[ok",
        ];
        it(`should return error message on failure ${invalidExpressionsMissingClosingParentheses}`, () => {

            invalidExpressionsMissingClosingParentheses.forEach((exp) => {

                let result = subject.parse(exp);
                expect(result.ErrorMessage.startsWith(ParenthesesParser.PARSING_ERROR)).to.be.true;
            });
        });
    });

    describe('Invalid parameters', () => {

        it(`should throw exception on empty string`, () => {
            expect(function () { subject.parse("");}).to.throw(ParenthesesParser.EXPRESSION_CANNOT_BE_NULL_OR_UNDEFINED);
        });
        it(`should throw exception on null string`, () => {
            expect(function () { subject.parse(null);}).to.throw(ParenthesesParser.EXPRESSION_CANNOT_BE_NULL_OR_UNDEFINED);
        });
        it(`should throw exception on undefined string`, () => {
            expect(function () { subject.parse(undefined);}).to.throw(ParenthesesParser.EXPRESSION_CANNOT_BE_NULL_OR_UNDEFINED);
        });
    });

    describe('Utility methods', () => {

        it(`isOpenParenthese() positive cases`, () => {
            ['(', "{", "["].forEach((c) => {
                expect(subject.isOpenParenthese(c)).to.be.true;
            });
        });
        it(`isOpenParenthese() negative cases`, () => {
            ['a', "b", "c"].forEach((c) => {
                expect(subject.isOpenParenthese(c)).to.be.false;
            });
        });
        it(`isCloseParenthese() positive cases`, () => {
            [')', "}", "]"].forEach((c) => {
                expect(subject.isCloseParenthese(c)).to.be.true;
            });
        });
        it(`isCloseParenthese() negative cases`, () => {
            ['a', "b", "c"].forEach((c) => {
                expect(subject.isCloseParenthese(c)).to.be.false;
            });
        });
    });
});


Wednesday, February 28, 2018

How to traverse a binary tree in JavaScript?

Overview 

Based on Traverse a Tree - Introduction. How to traverse a binary tree recursively

  • Pre-Order, 
  • In-Order, 
  • Post-Order 
  • Breadth-First
using mocha+chai test framework.

Github Repo: TreeTraversalJS

Source Code


let Queue = require('./Queue');

let print = console.log;

function TreeTraversal() {

    this.PathResult = [];

    this.init = function(first) {

        if(first) this.PathResult = [];
    }
    this.end = function(first) {

        if(first) print(`Path:${JSON.stringify(this.PathResult)}`);
    }
    this.processNode = function(node) {

        this.PathResult.push(node.value);
    }
    this.recursively_PreOrderTraversal = function (t, first) {

        this.init(first);
        this.processNode(t);

        if(t.left) this.recursively_PreOrderTraversal(t.left);
        if(t.right) this.recursively_PreOrderTraversal(t.right);

        this.end(first);
    }
    this.recursively_InOrderTraversal = function (t, first) {

        this.init(first);
        if(t.left) this.recursively_InOrderTraversal(t.left);

        this.processNode(t);

        if(t.right) this.recursively_InOrderTraversal(t.right);

        this.end(first);
    }
    this.recursively_PostOrderTraversal = function(t, first) {

        this.init(first);

        if(t.left) this.recursively_PostOrderTraversal(t.left);
        if(t.right) this.recursively_PostOrderTraversal(t.right);

        this.processNode(t);
        this.end(first);
    }
    this.breadthFirst = function(t) {

        this.init(true);
        let q = new Queue();
        q.enqueue(t);

        while(!q.isEmpty()) {

            let node = q.dequeue();

            this.processNode(node);

            if(node.left) q.enqueue(node.left);
            if(node.right) q.enqueue(node.right);
        }
        this.end(true);
    }
}

module.exports = TreeTraversal;


Unit tests


let assert = require('chai').assert;
let expect = require('chai').expect;
let TreeTraversal = require('../src/TreeTraversal');

/*
                             F
                         /      \
                         B       G
                       /  \       \ 
                       A  D        I
                         / \      /
                        C   E    H

*/
let root = {
    value : "F",
    right : {
        value: "G",
        right:{
            value:"I",
            left : {
               value:"H" 
            }
        }
    },
    left:{
        value:"B",
        left : {
            value:"A"
        },
        right :{
            value:"D",
            left :{
                value:"C"
            },
            right : {
              value:"E"
            }
        }
    }
};

let print = console.log;

function arrayEqual(a0, a1) {
    return a0.join() == a1.join();
}

describe('TreeTraversal', () => {

    let subject;

    before(() => {
        subject = new TreeTraversal();
    });

    describe('recursively_PreOrderTraversal', () => {

        let expected = ["F","B","A","D","C","E","G","I","H"];
        it(`should return ${expected}`, () => {

            subject.recursively_PreOrderTraversal(root, true);
            expect(arrayEqual(expected, subject.PathResult)).to.be.true;
        });
    });
    describe('recursively_InOrderTraversal', () => {

        let expected = ["A","B","C","D","E","F","G","H","I"];
        it(`should return ${expected}`, () => {

            subject.recursively_InOrderTraversal(root, true);
            expect(arrayEqual(expected, subject.PathResult)).to.be.true;
        });
    });
    describe('recursively_PostOrderTraversal', () => {

        let expected = ["A","C","E","D","B","H","I","G","F"];
        it(`should return ${expected}`, () => {

            subject.recursively_PostOrderTraversal(root, true);
            expect(arrayEqual(expected, subject.PathResult)).to.be.true;
        });
    });
    describe('breadthFirst', () => {

        let expected = ["F","B","G","A","D","I","C","E","H"];
        it(`should return ${expected}`, () => {

            subject.breadthFirst(root, true);
            expect(arrayEqual(expected, subject.PathResult)).to.be.true;
        });
    });
});


Tuesday, February 6, 2018

git reminder

# Git command summary

## Copy a repo locally

```bash
 git clone url
``` 

## Status

 git status

## Get latest of develop branch:

 git pull
 git fetch -all
 git merge origin/develop

## Branch

```bash
 # Create
 git checkout -b BRANCH-NAME
 # Switch
 git checkout BRANCH-NAME
 # Rename a local branch
 git branch -m BRANCH-NAME BRANCH-NAME
 # Last commits on each branch
 git branch -v
 # Which branches are already merged into the branch you’re on
 git branch --merged
```

# Editor and merge tool

```bash
 # Set up editor:
 git config --global core.editor notepad
 # Set up a diff tool:
 # https://sourceforge.net/projects/kdiff3/files/
 # kdiff3.exe must be in the path
 git config --global merge.tool kdiff3
``` 

# undo commited change ahead of remote
git reset --soft HEAD~1

## Undo

```bash
 # Undo unstaged changes
 git checkout .
 git checkout /folder/file.js
 # Undo unstaged and staged changes
 git reset --hard 
 # Undo change commite in the wrong branch, but keep the changes
 git log # to find the hash for the change
 git reset --mixed 2c41838da2738c0e1e23336fe48c3e4bae10d5f6
 # Revert a change that you have committed
 git revert  
 # Remove untracked files (new files)
 git clean -f
```

# How to change temporary changes - Stash (Selveset)
```bash
 git stash
 git pull
 git branch -m FredBundleStudy
 git stash pop
``` 

#How to delete a repo locally?

```bash
c:\myFolder> attrib -s -h -r . /s /d
c:\myFolder> del /F /S /Q /A .git
c:\myFolder> rmdir .git
```

Saturday, January 27, 2018

JavaScript unit tests with Jasmine and Karma

Overview




Jasmine and Karma installation

npm install // Install all the packages from package.json

npm install --save-dev jasmine
npm install --save-dev karma
npm install --save-dev karma-jasmine karma-chrome-launcher

Installs Karma dependencies; replace with whatever you have installed, e.g. chrome, firefox, or ie.


ESLint Installation

Install ESLint https://eslint.org/docs/user-guide/getting-started

npm install eslint --save-dev

Command Line

For developement

node_modules\.bin\karma start

For Build System

node_modules\.bin\karma start --single-run

To produce ESLint json config file

node_modules\.bin/eslint --init

To lint a file

node_modules\.bin\eslint yourfile.js

Github Repo

git remote add origin https://github.com/fredericaltorres/FuncsJS.git
git remote -v
git push -u origin master

Saturday, January 6, 2018

C# Azure Function sending SMS message

Overview

An example using an Azure Function written in C# (scripting) to send text message using Twilio. The full source code is on github.

One of the key issue was to reference the Twilio.Api.dll.

From the platform Feature Dialog of the Azure Function, in the Azure Portal
  • Open KUDU Powershell console 
  • Create a ref folder in the main source folder
  • Drag and drop the Twilio.Api.dll from your desktop to the top file system in the browser





To reference the DLL from the main source file use the following syntax.
#r "D:\home\site\wwwroot\RequestSmsSending\ref\Twilio.Api.dll"



Azure Function Run Method 


#load "SendSmsHelper.csx"
#load "AzureFunctionHelper.csx"

using System.Net;

public static async Task&tl;HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{    
    var ah = new AzureFunctionHelper(req, log);

    ah.Log(log, $"-- SendSMS --");

    string smsID    = null;
    var smsText     = await ah.GetParameter("smsText");
    var responseMsg = $"Invalid parameters";
    var to          = await ah.GetParameter("to", SendSmsHelper.FRED);
   
    if(smsText == null) { 

        ah.Log(log, responseMsg);
    }
    else {

        var finalSmsText = $"[{DateTime.Now}][{smsText}]";
        smsID            = SendSmsHelper.SendSMS(finalSmsText, to);
        responseMsg      = $"To:{to}, SmsID:{smsID}, SmsText:'{finalSmsText}'";
        ah.Log(log, responseMsg);
    }
    return await ah.GetResponse(smsID != null, responseMsg);
}


Wednesday, December 27, 2017

JavaScript ES6 filter(), take() and range() with iterator


FuncJS Github Repo: FuncJS

      //

      let filter = function * (items, predicate) {

          for(let item of items)
              if(predicate(item))
                  yield item;
      }

      let take = function * (items, number) {

          let count = 0;
          if(number < 1) return;
          for(let item of items) {

              yield item;
              count += 1;
              if(count == number) return;
          }
      }
      
      let range = function * (start, end) { 
        
        let current = start;
        while(current <= end) {

          let delta = yield current;
          current += delta || 1;
        }
      }

      let count   = 0;
      let found   = null;
      let names   = ["Joy","Sue","Bob","Tom", "Sophie"];

      for(let e of take( filter( names, e => e.startsWith("S")), 1 ) ) {

          count += 1;
          found = e;
      }
 
      
      let result    = [];
      let iterator  = range(1, 10);
      let next      = iterator.next();

      while(!next.done) {

        result.push(next.value);
        next = iterator.next(2);
      }