Category Archives: JavaScript

primary-node

Primary node election in distributed computing

Primary node can help with coordination of multiple node deployed in a cloud. One of the projects I’ve worked on had a NodeJS worker that ran multiple types of tasks. I wanted to upgrade this setup in order to be easily scalable, have a primary node (or coordinator) that triggers the tasks and continue processing even when some of the nodes fail.

The Checklist

  • All nodes may participate in an “election” to choose the coordinator
  • Support any number of nodes, including 1 node setup
  • Handle node fail (even the coordinator node) without impacting the flow
  • Allow new nodes to join the party
  • Don’t depend on an expensive technology (paid or resource hungry)

Besides the main scope of the solution I also needed to ensure that the election of the coordinator follows these 3 basic principles:

  • Termination: the election process must complete in a finite time
  • Uniqueness: only one node can be coordinator
  • Agreement: all other nodes know who’s the coordinator.

After I established that I have all the scenarios in mind, I started investigating different algorithms and solutions that the market uses (Apache Zookeeper, Port Locking, Ring Networks). However, most of these require a lot of setup or were incompatible in a multi server setup and I also wanted to embrace a KISS approach so continue reading to see the solution.

The Primary Node Election Algorithm

  1. Node generates a random numeric id
  2. Node retrieves a COORDINATOR_ID key from Redis
  3. If key !NULL
    • We have a coordinator
    • Wait Z minutes (e.g. Z = 1 hour)
    • GoTo Step2
  4. If key NULL
    • No coordinator announce
    • Push the id from Step1 in a Redis list
    • Waits X seconds (depending on how long the deployment takes, e.g. 10 seconds)
    • Retrieve all items in the list and extract the highest number
    • If result === node id
      • Current node is primary
      • Set Redis key COORDINATOR_ID with expiry Z+X
      • Do all the hard work 🙂
    • Wait Z minutes
    • GoTo Step2

Downside of this solution is that if the coordinator node fails, it actually takes 2*Z until a new election takes place.

There’s room for improvement so please don’t hesitate to leave a feedback 🙂

What is X-WSSE Token Authentication and how does it work

Learn the basics of X-WSSE Token Authentication and how to authorize requests using X-WSSE header authentication.

X-WSSE Token Authentication can be used to authenticate backend-to-backend integrations using client_id and client_secret properties. The main benefit of this type of authentication is that the client_secret value never leaves the backend of the integrating client, and that each token, even if lost, is only valid for 5 minutes.

The X-WSSE Token is a string with the following format, usually a single HTTP header line which is broke down into multiple lines for easier readability:

X-WSSE: UsernameToken
Username="USERNAME",PasswordDigest="ASDFbasEHAPRo395MBANgoaiERJGJHSOSLGUsernameToken Username="68037425-fa69-49da-8715-fa393dc55471", PasswordDigest="OWRkZGRjMjk3ZjhiOGFhZmMzNGIzMjAwMWIyNmNjY2JkMTM2M2E5OGFlMGM2ZDI3OGIzZmQ5ZDAwY2RiODMzZg==", Nonce="ee2e8c783398782fd63af15141a1cb62", Created="2019-03-14T16:17:24.211Z"==",Nonce="b35f7341829e35d89851497a82894f",Created="2019-03-20T12:10:20Z"

I’ll briefly describe each component of the X-WSSE Token:

X-WSSE

The name of the HTTP header that must be present in order to authorize the request.

UsernameToken

Value represents the authentication method of the use X-WSSE Token. Currently X-WSSE only supports UsernameToken type of authentication.

Username

The client_id property that you should generate for each integration of X-WSSE Token.

PasswordDigest

Field specifies the hashed token that will authorize the reuqest. For each request a new hash must be generated. Check my other posts and learn how to generate the X-WSSE Token using different server-side programming languages

Computing the Password Digest

Computing the password digest involves 5 simple steps:

  1. Generate random 16 byte Nonce formatted as 32 hexadecimal characters.
  2. Retrieve the current timestamp in ISO8601 format.
  3. The properties nonce, timestamp, secret should be concatenated in this order.
  4. Compute the SHA256 hash value of the string from #3 and convert it to hexadecimal format
  5. Encode the value from #5 in BASE64 and obtain the PasswordDigest

Nonce

Random value with the purpose to make your request unique so it cannot be replicated by unknown parties. This string is always 16 bytes long and should be represented as a 32 characters long hexadecimal value.

Created

This field contains the current UTC, GMT, ZULU timestamp (YYYY-MM-DDTHH:MM:SS) according to the ISO8601 format. e.g. 2018-05-20T12:51:45+01:00

Now you know what is a X-WSSE Token and the purpose of each of its components so let’s go to the Implementation. Check my other X-WSSE articles and learn more.


Convert seconds to Days, Hours, Minutes, Seconds

Learn how to convert number of seconds into days, minutes, hours and seconds.


That’s it. You can now create a countdown timer, display the difference between two dates or just print  the time until something great happens.

var seconds = 1001110 // 11 days 14:05:10

// compute the number of days
var days = Math.floor(seconds / (3600*24))
seconds -= days*3600*24

// compute the number of hours
var hours = Math.floor(seconds / 3600)
seconds -= hours*3600

// compute the number of minutes
var minutes = Math.floor(seconds / 60)
seconds -= minutes*60

You now have 4 variables with values as follows:

days === 11
hours === 14
minutes === 5
seconds === 10

Bonus! Learn how to pad the values with 0 so that they look pretty 😀

function str_pad_left (string, pad, length) {
     return (new Array(length+1).join(pad)+string).slice(-length)
}

console.log(str_pad_left(minutes, '0', 2)) // "05"

Check this article to learn how to create a countdown timer.

Google Ads placement In WordPress Sidebar

Google AdSense Ad Units options

Writing articles and maintaining a website takes some time and is not exactly free. If you want to start monetizing your WordPress website you could use Google AdSense and place Google Ads in your website or mobile app.

There are a few steps until you can manage to show ads on your websites. Let’s get started:

AdSense Account Activation

First thing we need is to create a Google AdSense account. This is the place from where we obtain our Google Ads. Start by signing into https://www.google.com/adsense and init the account activation process. This usually takes between 3-10hours but it depends on your account and website.

You’ll be sent an approval email so soon as you receive it you’re good to go.

Ad Unit Creation

Google AdSense Menu

Head to AdSense webpage again and hit Ads->Ad units.

Each zone of the website where any ad will appear should have a dedicated ad unit.


We’re going to create an ad for the sidebar so choose Text & display ads. Enter an unique id for your add which can be something like WEBSITE_AD_SIDEBAR then click save.

You can now obtain the Ad Code which must be added into your website.


Placing Ads On Website Sidebar

How to create HTML Text Widget

Head to your Worpress Admin Menu.

Enter Appearance->Widgets.

Drag a new Custom HTML to your siderbar and fill the content with the exact Ad Code you get from AdSense.

Click Save!

And Voila, you know have Ads on your WordPress Sidebar.

Vue Countdown Timer Component

At the end of this post you’ll learn how to implement a basic vue countdown timer component.

In a web project I built I needed to show the user a countdown timer until the UI/options will expire.

So I ended up building a quite simple Vue Component that can be integrated in any app and that can be easily extended for any needs.

The template of the Vue Countdown Timer Component looks like this.

I’ve also used Bootstrap class to make the timer red when there’s no more time left.

<template>
    <div>
        <p :class="{'text-danger': total<=0}">
            <strong>{{minutes}}</strong>
            <strong>:</strong>
            <strong>{{seconds}}</strong>
        </p>
    </div>
</template>

The controller of the component:

export default {
    props: {
        time: {
            type: Number,
            default: 0
        }
    },
    data: function () {
        return {
            total: '',
            minutes: '--',
            seconds: '--',
            interval: 0
        }
    },
    mounted: function () {
        this.total = parseInt(this.time, 10)
        this.interval = setInterval(() => {
            this.tick()
        }, 1000)
    },
    methods: {
        str_pad_left: function (string, pad, length) {
            return (new Array(length+1).join(pad)+string).slice(-length)
        },
        tick: function () {
            var minutes = Math.floor(this.total / 60)
            var seconds = this.total - minutes * 60
            this.minutes = this.str_pad_left(minutes, '0', 2)
            this.seconds = this.str_pad_left(seconds, '0', 2)

            if (this.total <= 0) {
                clearInterval(this.interval)
                this.$bus.$emit('Timer/stop')
            }

            this.total -= 1
        }
    }
}

What it does:
The props defines which parameter to receive from the parent component. In our case it represents the number of seconds that the timer will start from.

The data contains properties required for showing the current state of the timer and for allowing us to control the interval handler.

When mounted, the component reads the time parameter and initializes the interval at which it will update the progress.

Tick method is executed as defined in the mounted interval. It will generate pretty minutes and seconds padded with ‘0’.

When the total seconds get to 0 we’ll also $emit an event. See my previous post for learning how to implement Observer Pattern in Vue.

 

Integrating the timer in our app is as easy as:

<Timer :time="300" />

That’s all. Our Vue countdown timer components is ready.

Vue Observer Pattern Implementation

Learn how to implement Vue Observer Pattern in your web app.

Probably one of my favorite design patterns is the Observer Pattern.
This design pattern allows you to subscribe and emit events from components of your app.

 

Different web frameworks offer different implementation of the Observer app.

Lucky me, implementing Observer in VueJS is piece of cake.

Actually the Observer in VueJS could be another Vue instance that we pass or make accessible by all our components.

import Vue from 'vue'
// create a new Bus which will handle all our events
const EventBus = new Vue()
// We need to assign the bus to the root component
Vue.prototype.$bus = EventBus

That’s all needed for the setup part.

You can now use this.$bus in all your Vue Components to subscribe and emit and dispatch events.

...
// some random component emits events
methods: {
    logout: function() {
        this.$bus.$emit('Some_Event/name', user)
    }
}
...
// some random component subscribes to the event
created: function() {
    this.$bus.$on('Some_Event/name', (data) => {
       this.logout_user(data)
    })
}

There are two possible ways of generating the events and it mostly depends on who we want to receive that event.

$emit – targeting whole app

The $emit method will trigger an event in the current instance.
This means that all subscribers will be notified of this event.

$dispatch – targeting parent components

The $dispatch method propagates the event up in the parent chain.
The first parent subscriber will stop the event from propagating further unless it returns true.

In my next post I’ll describe how to create a Countdown Timer Component in VueJS.
Adios!

Socket.IO AngularJS Wrapper

I’ve been playing around with Socket.IO and AngularJS. To make things easier I created this service which can be used for transferring data between the client (which could be a web page) and a NodeJS server.

The app is served by NodeJS so the Socket.IO server is listening on same location.

'use strict';

angular
.module('APP')
.factory('$WS', function($rootScope) {
    var self = this;

    self.ready = false;

    self.socket = io.connect(location.host, {
        'connect timeout':       100,
        'reconnection delay':    100
    });

    self.socket.on('init', function() {
        console.log('init');
    });

    self.socket.on('disconnect', function() {
        console.log('socket disconnected');
    });

    self.socket.on('connect', function() {
        console.log('socket connected');
    });

    return {
        ready: function(callback) {
            if(self.ready) {
                callback();
                return;
            }

            self.socket.on('connect', function() {
                $rootScope.$apply(function() {
                    self.ready = true;
                    callback.apply(self.socket);
                });
            });
        },
        on: function(eventName, callback) {
            self.socket.on(eventName, function() {
                var args = arguments;

                $rootScope.$apply(function() {
                    callback.apply(self.socket, args);
                });
            });
        },
        emit: function(eventName, data, callback) {
            self.socket.emit(eventName, data, function() {
                var args = arguments;
                $rootScope.$apply(function() {
                    if(callback) {
                        callback.apply(self.socket, args);
                    }
                });
            });
        }
    };
});

Usage:

angular
.module('APP')
.controller('TestController', ['$scope', '$WS', function($scope, $WS) {

    $scope.messages = [];

    // Connect websocket
    $WS.ready(function() {
    
        // Receive message
        $WS.on('chat/message', function(data) {
            
            // Validate input data
            if(data.message_id) {
                console.log(data);
                $scope.messages.push(data);
            }
        });
    });

    // You can add another ready state listener for the same connection
    // Let's consider we have a method which sends messages
    $scope.send_message = function(msg_title, msg_value) {
        
        $WS.ready(function() {
            // Emit message
            $WS.emit('chat/message', {
                title:    msg_title,
                message:  mgs_value
            });
        });
    };

}]);

 

This is just basic usage.  Will be back with NodeJS & Socket.IO server example.

Google Maps JavaScript Wrapper

Some of the projects I’ve implemented required some dynamic or static maps.

Of course most powerful maps library at that time was Google Maps.

The wrapper allows the insertion of markers with custom icon, circles, polylines and setting the center and zoom of the map.

Here’s one version of the JavaScript Google Maps Wrapper that I’ve created:

function GMaps(opt) {
    this.map          = null;

    this.circles      = [];
    this.markers      = [];
    this.polylines    = [];

    this.m_icon_path  = opt.icon_path || null;
    this.m_icon       = null;
    
    this.lat          = opt.lat || 45.8805435;
    this.lng          = opt.lng || 24.9582169;
    this.zoom         = opt.zoom || 7;

    this._init(opt);
}

GMaps.prototype._init = function(opt) { 
    var self = this;

    if(opt == null) {
        opt = {};
    }

    var map_options = {
        zoom:               self.zoom,
        center:             new google.maps.LatLng(self.lat, self.lng),
        mapTypeId:          google.maps.MapTypeId.ROADMAP,
        streetViewControl:  false,
        scaleControl:       false,
        mapTypeControl:     false,
        panControl:         false,
        zoomControlOptions: {
            style: google.maps.ZoomControlStyle.SMALL
        }
    };

    self.map = new google.maps.Map(document.getElementById(opt.element), map_options);

    if(self.icon_path) {
        self.icon = new google.maps.MarkerImage(self.icon_path, null, null, null, new google.maps.Size(20, 26));
    }
};

GMaps.prototype.check_resize = function() {
    var self = this; 
    
    google.maps.event.addListenerOnce(self.map, 'idle', function() {
        google.maps.event.trigger(self.map, 'resize');
        self.map.setCenter(new google.maps.LatLng(self.lat, self.lng));
    });
};

GMaps.prototype.clear_markers = function() {
    for(var i=0; i<this.markers.length; ++i) {
        if(this.markers[i].circle != null) {
            this.markers[i].circle.setMap(null);
        }

        this.markers[i].setMap(null);
    }

    this.markers = [];
};

GMaps.prototype.clear_polylines = function() {
    for(var i=0; i<this.polylines.length; ++i) {
        if(this.polylines.markers != null) {
            for(var y=0; y<this.polylines.markers.length; ++y) {
                this.polylines.markers[y].setMap(null);
            }
        }

        this.polylines[i].setMap(null);
    }

    this.polylines = [];
};

GMaps.prototype.clear_circles = function() {
    for(var i=0; i<this.circles.length; ++i) {
        this.circles[i].setMap(null);
    }

    this.circles = [];
};

GMaps.prototype.reset = function() {
    this.clear_markers();
    this.clear_polylines();
    this.clear_circles();
};

GMaps.prototype.set_icon_path = function(path) {
    this.icon_path = path;

    if(this.icon_path) {
        this.icon = new google.maps.MarkerImage(this.icon_path, null, null, null, new google.maps.Size(71, 71));
    }
};

GMaps.prototype.set_zoom = function(zoom) {
    this.map.setZoom(zoom);
};

GMaps.prototype.set_center = function(lat, lng, opt) {
    this.map.setCenter(new google.maps.LatLng(lat, lng));

    if(opt && opt.zoom) {
        this.map.setZoom(opt.zoom);
    }
};

GMaps.prototype.add_marker = function(lat, lng, opt) {
    if(opt == null) {
        opt = {};
    }

    var m = new google.maps.Marker({
        position: new google.maps.LatLng(lat, lng),
        map:      this.map,
        title:    opt.title
    });

    if(this.icon) {
        m.setIcon(this.icon);
    }

    if(opt.circle) {
        m.circle = new google.maps.Circle({
            center:       new google.maps.LatLng(lat, lng),
            map:          this.map,
            strokeWeight: 0,
            fillColor:    opt.circle_fill || '#F00',
            radius:       opt.circle_radius || 50
        });
    }

    this.markers.push(m);
};

GMaps.prototype.add_polyline = function(items, show_origin) {
    var path = [];

    for(var i=0; i<items.length; ++i) {
        path.push(new google.maps.LatLng(items[i].lat, items[i].lng));
    }

    var p = new google.maps.Polyline({
        path: path,
        map:  this.map
    });
    
    if(show_origin) {
        p.markers = [];
        p.markers.push(this.add_marker(path[0].lat(), path[0].lng(), {}));
        p.markers.push(this.add_marker(path[path.length-1].lat(), path[path.length-1].lng(), {}));
    }

    this.polylines.push(p);
};

GMaps.prototype.add_circle = function(lat, lng, opt) {
    if(opt == null) {
        opt = {};
    }

    this.circles.push(new google.maps.Circle({
        center:       new google.maps.LatLng(lat, lng),
        map:          this.map,
        strokeWeight: 0,
        fillColor:    opt.fill || '#F00',
        radius:       opt.radius || 50
    }));
};

Usage:

Create element:

<div id="map-wrapper"></div>

Set element style:

<style type="text/css">
    #map-wrapper {
        width: 100%;
        height: 100%;
    }
</style>

Create instance of Google Maps Wrapper:

var map_instance = new GMaps({
    element:    'map-wrapper',
    zoom:       7,
    lat:        45.8805435,
    lng:        24.9582169,
    icon_path:  'http://www.catalinmunteanu.com/wp-content/uploads/2015/01/gmaps_marker.png'
});

// Setting map center
map_instance.set_center(45.8805435, 24.9582169, {zoom: 7});

// Setting map zoom
map_instance.set_zoom(7);

// Change/Set marker icon path (or use default icon)
map_instance.set_icon_path('http://www.catalinmunteanu.com/wp-content/uploads/2015/01/GMaps_marker.png');

// Create marker (circle is optional)
map_instance.add_marker(45.8805435, 24.9582169, {
    circle:         true,
    circle_radius:  20000
});

// Create polyline
map_instance.add_polyline([
    {lat: 45.6725422, lng: 23.567376},
    {lat: 45.0239766, lng: 24.887982},
    {lat: 45.6725422, lng: 26.2150817}
], true);

// Create circle
map_instance.add_circle(46.5037588, 24.2036717, {radius: 20000, fill: '#336699'});
map_instance.add_circle(46.5037588, 25.6674779, {radius: 20000, fill: '#336699'});

// To clear the map use
// map_instance.clear_markers();
// map_instance.clear_polylines();
// map_instance.clear_circles();

// Or with just one call
// map_instance.reset();

 

If  you like this article don’t forget to share it.

Senior JavaScript Interview Test

A few weeks ago a team that I collaborated with asked me to create a JavaScript Interview Test for seniors.

The third part of the interview test also contains answers.

My opinion is that if you ever use this test and the candidate can answer correctly to  1/3 of the questions, well you should definitely hire him.

Go ahead and test your skills:

 

Part I. Questions. [30 minutes, general JavaScript knowledge]

#1. Can you name some Javascript frameworks? Why would you recommend them?

#2. Do you use any Javascript code validators? Can you name one?

#3. Do you unit test your Javascript code? If yes, what frameworks are you using?

#4. Can you name the Javascript interpreter used by Mozilla Firefox? Or any other of the browsers?

#5. What is JSON? What is it used for?

#6. What is JSONP? Can you explain how it works?

#7. Can you write an example of a Javascript generator?

#8. What frameworks have you used for creating 2D, 3D animations?

#9. Describe how would you implement an algorithm to generate random numbers.

 

Part II. Option I. Classic Snake Game. [2 hours, medium developer]

Requirements:

  • The game must be implemented in a typical 2-dimensional layout.
  • The snake should be able to grow significantly within the bounds of the map (the grid size should be at least 20×20)
  • The user may move the snake using the arrow keys, however, the snake cannot double back on itself (e.g. if it is going West it cannot go East without first going North or South). A snake should be able to travel in all 4 directions: up, down, left, right (North, South, West, East).
  • Snake starts off as length 1, each time it eats a “food” object it grows +1 in length
  • Food objects are randomly placed in locations other than those occupied by the snake
  • Only one Food object is visible at any time
  • If the Snake hits itself or a wall the game is ended
  • When the game ends, the score(number of eaten “food”) is displayed followed by a button “Restart” which restarts the game.
  • The task must be completed with HTML5 features: you can choose from Canvas or SVG

 

Part II. Option II. Brick Breaker Game. [2 hours, senior developer]

Requirements:

  • The game must be implemented in a typical 2-dimensional layout
  • The objective is to smash a wall of bricks by deflecting a bouncing ball with a paddle.
  • The user may move the paddle horizontally using the left/right arrow keys.
  • When all the bricks have been destroyed the game is won.
  • If the ball hits the bottom border 3 times the game is lost.
  • The task must be completed with HTML5 features: you can choose from Canvas or SVG

 

Part III. Solve and explain the exercises. [30 minutes, senior developer]

#1. What does alert(x) and alert(y) output?

(function() {
    var x = y = 1;
}) ();

alert(x);
alert(y);

#2. What is the output of alert(window)?

(function() {
    alert(window);
    var window = window;
}) ();

#3. What does foo() call return?

function foo()
{
    return
    {
        haha: "ha"
    };
}
foo();

#4. What is the output for each of the following calls?

// a
function Dude(name) {
    this.name = name;
    return {name: 'Doug'};
}
new Dude('Bob');

// b
function Dude(name) {
    this.name = name;
    return [1, 2, 3];
}
new Dude('Bob');

// c
function Dude(name) {
    this.name = name;
    return 3;
}
new Dude('Bob');

#5. What is the output for the following sequences?

// a
parseInt('foo');

// b
parseInt('foo', 16);

#6. Output for following console.log calls:

var a = 1
    b = 1;

(function() {
    var a = 2
        b = 2;
} ())

console.log(a);
console.log(b);

#7. Output for following line:

[,,,].join()

#8. What do the anchors alert when clicked?

<a href="#">link1</a>
<a href="#">link2</a>
<a href="#">link3</a>

<script>
    var el = document.getElementsByTagName('a');
    for(var i = el.length; i--;) {
        el[i].onclick = function() {
            alert(i);
            return false;
        }
    }
</script>

#9. What’s the content of the following array after the evaluation?

[typeof 'hi' === 'string', typeof new String('hi') === 'string']

#10. What’s the output for this code:

function Point() {
    this.x = 20;
    this.getX = function() {
        return this.x;
    };
}

var a = new Point();
var f = a.getX;
alert(f());

#11. What are the values of x and y after the execution of the following code?

var y = 1, x = y = typeof x;

#12. What does this code sequence output:

var x = [typeof x, typeof y][1];

typeof typeof x;

#13. What does the following code sequence output:

(function f(){
    function f(){ return 1; }
    return f();
    function f(){ return 2; }
})();

 

Answers to Part III

#1. It’s treated like: var x = (y = 1); thus, ‘y=1’ creates an auto-global since there’s no binding ‘var’ statement for it. then that value gets copied into properly defined local var ‘x’.

alert(x); // undefined

alert(y); // 1

#2. Because of ‘hoisting’, all variable declarations will be executed immediately at the top of a function scope. However, the variable initializations are not hoisted. So, local variable ‘window’ is declared but uninitialized/’undefined’.

alert(window); // undefined

#3. returns ‘undefined’. Semicolons in javascript are optional but the interpreter just inserts them for you at certain newline characters if it thinks they are missing. A return statement followed by a new line tells the JS interpreter that a semicolon should be inserted after that return.

#4. Returning a primitive type from a constructor(number, string, date) will ignore the return value and return the originally initialized object, but otherwise, the returned value overrides.

  1. a) {name: ‘Doug’}
  2. b) [1, 2, 3]
  3. c) {name: ‘Bob’}

#5. parseInt should always have the radix parameter supplied

  1. a) NaN
  2. b) 15

#6. Since JavaScript has ‘automatic semicolon insertion’ for some statements like ‘var’, a semicolon gets inserted after ‘a = 2’, and variable ‘b’ gets declared as a global!

console.log(a); // prints 1

console.log(b); // prints 2

#7.  Trailing commas are allowed in javascript and are automatically removed.

The above array is evaluated as [undefined, undefined, undefined]

[,,,].join() // outputs “,,”

#8. All anchors will output -1 when clicked

#9. [true, false]

#10. undefined

#11. x and y are undefined

#12. “string”

#13. 2

 

If  you like this article don’t forget to share it.

JavaScript Prototypal Inheritance Pattern

This is pretty basic stuff but I’ll just place it here in case someone searches for a way to achieve inheritance in JavaScript.

 

// JavaScript doesn't have classes but same behavior can be easily obtained using functions
// Let's consider a class Person
function Person() {
    this.name   = '';
    this.birth  = {
        'year':  -1,
        'month': -1,
        'day':   -1
    };
}

// Basic setters and getters for the class attributes
// I'll skip the validation since we're not focusing on that now
Person.prototype.set_name = function(name) {
    this.name = name;
};

Person.prototype.set_birth = function(year, month, day) {
    this.birth.year  = year;
    this.birth.month = month;
    this.birth.day   = day;
};

Person.prototype.get_name = function() {
    return this.name;
};

Person.prototype.get_birth = function() {
    return this.birth.day + '/' + this.birth.month + '/' + this.birth.year;
};

// Student Class
function Student() {
    this.school = '';
}

// We inherit all properties from the Person Class
Student.prototype = new Person();

// We need to set the constructor otherwise Student instances would have Person constructor
Student.prototype.constructor = Student;

// Student setters and getters
Student.prototype.set_school = function(school) {
    this.school = school;
};

Student.prototype.get_school = function() {
    return this.school;
};

Usage of above described classes:

// New Student instance
var student1 = new Student();

student1.set_name('Catalin');
student1.set_birth(1900, 1, 1);
student1.set_school('A.I.Cuza');

console.log(student1.get_name());
console.log(student1.get_birth());
console.log(student1.get_school());