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

How to delete a repo locally?


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);
      }

JavaScript Class With Iterator (ES6)

//
//
      class Company {
          
          constructor() {
              this._employees = [];
          }
          addEmployees(...names) {
              this._employees = this._employees.concat(names);
          }
          *[Symbol.iterator]() {
              for(let e of this._employees)
                yield e;
          }
      }

      let count   = 0;
      let company = new Company();
      company.addEmployees("Fred","Joe","Tommy","Tom", "Sophie");

      for(let employee of company) {

          console.log(employee);
      }