Click here to Skip to main content
Click here to Skip to main content

Challenges and Solutions - Architecture of a Modern Web Application - JavaScript - Part 2

, 23 Oct 2013
Rate this:
Please Sign up or sign in to vote.
JavaScript is a vital part of modern web applications. This article skim over some of JavaScript features.

Article Series

Introduction

Part 1 of this series showed a little bit of CSS 3 and JavaScript in action. Now we see a bit more of device side 'ninja' i.e., JavaScript. We will see challenges and solutions in the perspective of devices with limited battery life, computing power, and storage.

Figure - Where you want to run JavaScript?

JavaScript Today

JavaScript is a powerful language and people write code in various styles. There is a lot of script around, and script reuse is important to progress forward, may it be coming from Brendan Eich, Douglas Crockford, Ryan Dahl, or anyone else. To merge existing frameworks, it is important that we understand various styles in use.

Figure - Left to Right: Brendan Eich creator of JavaScript, Douglas Crockford major contribution in YUI and JSON, and Ryan Dahl creator of Node.js

Before I go further, whenever you find a badly explained example, I recommend playing with it in jsfiddle! Smile | :)

A Class and Object

In JavaScript you declare a class by declaring its constructor function which is 'nothing' more than a 'regular' JavaScript function.

function Button() {} // A Button class delcared

It is a convention in JavaScript community to use Title Case for a constructor function. The above code declares two things: a class Button, and its constructor function. With this function (or constructor function if you still wish to differentiate), you can create Button objects using the new operator:

var button1 = new Button();
var button2 = new Button();

A Class is just a regular function

The code above will allocate two memory locations and executes code inside the Button() function twice. As mentioned earlier, under the hood Button 'class' or 'constructor function' is nothing but a 'regular' JavaScript function. In fact 'every' JavaScript function is an instances of the Function class.

var add = new Function("a", "b", "return a + b"); 
add(2, 6); // call the function 
// As function is object it can be used like a 'regular object'
// you can return function from a function or send it as argument
// and save it in a var
function addFactory()  {  
    var addMethod  = function (a, b)  {
        return a + b;
    }
    
    return addMethod;
}

var x = addFactory();

alert(x(1, 2)); // return 3

In fact, all objects in JavaScript are descended from Object; and inherit methods and properties from Object.prototype, although they may be overridden.

typeof Button; // returns "function"
typeof button1; // returns "object"

button1 instanceof Button // true

Constructor with parameter

You can have a constructor with some parameters just like regular JavaScript function:

function Button(text) {
    
} 

Class Assets - Methods and Members

A class has two kinds of assets: members and methods. In following examples, we will progressively add private, privileged, public and static assets in a Button class. We will also take a first look at inheritance and access rules.

public

To have public members of class:

function Button(text) {
    this.text = text; // public member
}
var button = new Button("Submit");

button.text; // return 'Submit' 

private

And to have a private member i.e., one that is inaccessible in public methods:

function Button(text) {
    var visible; // private member
}

privileged

And to add privileged method i.e., one that can access private members:

function Button(text) {
    var visible;

    this.show = function() { // privileged method
    	visible = true;
    };
} 

It is important to remember that private members are declared and accessed without using this.

private method

To add private method hide():

function Button(text) {
    var visible;

    function hide() { // private method
    	visible = false;
    } 
} 

public method

And to add a public method resetText() and public member rounded:

function Button(text) {
    this.text = text; // public member

    var visible; // private member

    this.show = function() { // privileged method
    	visible = true;
    };

    function hide() { // private method
    	visible = false; // INCORRECT: this.visible = false; do not use 'this' for private member
    }
}

Button.prototype.rounded = false; // public member

Button.prototype.resetText = function() { // public method can not access private assets
    this.text = ""; // INCORRECT: text = ""; always use 'this' for public member
}

The key difference between public and privileged is that, a privileged method is created for every instance of the class while a public method is shared between all instances of a class. This becomes important if thousands of objects are created. We will see more on this later.

static

And to add a static member or method:

function Button(text) {
...   
}

Button.defaultText = "My Button"; // static member

Button.resetDefaultText = function() { // static method
    Button.defaultText = "";
};

inherit (or chain)

Figure - JavaScript search for method or member in all chained objects

As mentioned earlier, every JavaScript class is just a regular function. We also know, every function in JavaScript is an instance of the Function class. The Function class has a public property prototype which is used to chain objects together. When a child object is chained to a parent object, all non-private parent assets behave as if they are the part of the child object. If a method or member is not available in a child object, JavaScript looks into its parent prototype and this search continues until an object with prototype = null is found. Checkout this example:

function A() {
   this.num = 100;    
}

function B() {
}

function C() {
}

B.prototype = new A(); // A is parent of B
C.prototype = new B(); // B is parent of C

var x = new C()
x.num; // return 100 search C-->C.prototype-->B.prototype-->A
x.speed; // return undefined search C-->C.prototype-->B.prototype-->A.prototype-->Object.prototype-->null

You can see that chaining could be used to create inheritance as we will see below. But before we do that, I would like to point out that deep chaining could affect performance due to search. Also for a non-existent member, search will continue till the end of chain.

inherit using new

This example show how to inherit from Button class using new:

function Button(text) {
    this.text = text; 
}

function LinkButton(text, url) {
    Button.call(this, text); // call base class constructor
    this.url = url;
}

LinkButton.prototype = new Button(); // this will make Button a base class

var b = new LinkButton("Google", "http://www.google.com");

b  instanceof Button; // return true
b instanceof LinkButton; // return true

b.text; // calling base class public member

inherit using Object.create()

Figure - A large object could be initialized later using Object.call(this)

The new operator not only creates Button object but also calls its constructor. In the example above, the Button constructor is called twice, once at new Button() and then Button.call(this, text). This is a waste of CPU cycles. A better way is to use Object.create(), which only creates the object but does not call constructor. You could call the base class constructor later using Object.call().

function Button(text) {
    this.text = text; 
}

function LinkButton(text, url) {
    Button.call(this, text); // call base class constructor
    this.url = url;
}

LinkButton.prototype = Object.create(Button); // only create object, do not call Button constructor

var b = new LinkButton("Google", "http://www.google.com");

b  instanceof Button; // return true
b instanceof LinkButton; // return true

b.text; // calling base class public member

Nesting vs. prototype

It is perhaps timely to mention that, the code inside the Button constructor should be short (and execute fast) to reduce object creation time. Consider a case of creating hundreds of LinkButton objects and adding them to a list on a smart phone. On a smart phone, a quick object creation + initialization will eat less CPU cycles and result in increased battery life, which is usually 6 to 10 hours!

Figure - Running JavaScript on iPhones with 6 to 10 hours of battery life

Beside battery drain due to CPU usage, a function nested inside 'constructor function' is created for every new instance of class which will tax memory.

Figure - Typical RAM in smart phones

As nested functions are created for every object construction, keep public assets (i.e., methods and members) and initialization outside the constructor function whenever possible. This will keep object construction fast and footprint low.

// Good
function Button(text) {
    this.text = text; 
}

Button.prototype.resetText = function() { // public method
    this.text = ""; 
};
// Bad
function Button(text) {
    this.text = text; 
    this.resetText = function() { // PROBLEM: public method declared as privilaged
        this.text = ""; 
    };
}

Declare method inside constructor only if it is accessing private class assets or if the constructor is initializing a member with supplied argument. For all other cases use prototype to add class assets.

Figure - Recent smart phones are providing 'desktop-grade' CPU

Although recent smart phones are providing 'desktop-grade' CPU but nesting creates a level of scope and slows down name resolution.

Class & Object - Add or Remove Assets On-the-fly

Figure - JavaScript is like a flexible free-size T-shirt

Although a class in JavaScript acts as a 'blue print' for object creation, however you can add methods and members even after creating objects. 'on-the-fly' class asset is immediately added to 'all live' objects of that class while 'on-the-fly' object asset is only added to 'that particular' object instance only. Consider for example:

function Button(text) {
    this.text = text; 
}

var b1 = new Button("Tooltip Button");
var b2 = new Button("Normal Button");

b1.toolTip = "This tooltip public member is only for object 'b1'"; // on-the-fly 'object asset'
b2.toolTip; // ERROR: undefined

Button.prototype.resetText = function() { // on-the-fly 'class asset'
    this.text = ""; 
};

b1.resetText(); // OK
b2.resetText(); // OK too

Figure - Adding Class Asset - Add Stereo System in class Car

Just like you can add assets to class or object, you can delete them too.

delete b1.toolTip;

Button.prototype.resetText = undefined;

b1.toolTip; // undefined
b2.resetText(); // ERROR

Figure - Removing Object Asset - Remove Alarm System from object yourCar

On the fly asset management may be useful for composing a large object spread across many JavaScript files inline with Asynchronous Module Definition (AMD). Even for smaller objects, composition might be useful for example device capability detection and 'trimming' object as necessary.

Seal and Freeze Object (Not Class)

Figure - JavaScript provides various ways to stop on-the-fly asset add and remove

When we are talking about JavaScript, JScript, and ECMAScript are they 1 language or 3? I wanted to touch this subject in brief, so to safely say ECMA Script 5 has 'a way' to turn off on-the-fly asset add and remove in objects.

JavaScript is a Netscape and now Mozilla backed language while JScript is a similar version developed by Microsoft. In 1996 both Microsoft and Netscape agreed to develop their version of language based on ECMA standards, called ECMA Script or ES for short.

In ES5 (or JavaScript 1.8.5) compatible browsers, one can Seal() and Freeze() an object. You can not add or remove property in a Sealed object while Freezing adds to sealing, by making property value un-editable. If you only want to stop adding new properties, but existing one could be deleted use preventExtensions(). Seal, Freeze and Prevent Extensions are not applicable to Class. Consider examples below:

function Button(text) {
    this.text = text; 
}

var b = new Button("My Button");

Object.seal( b ); 
Object.isSealed( b ); // returns true
b.text = "Submit"; // OK
b.toolTip = "Mine"; // FAIL silently
delete b.text; // FAIL silently
Button.prototype.toolTip = "Mine"; // OK, only object is sealed not Button class

Object.freeze( b ); 
Object.isFrozen( b ); // returns true
b.text = "Submit"; // FAIL silently
delete b.text; // FAIL silently
Button.prototype.toolTip = "Mine"; // OK, only object is freezed not Button class

Object.preventExtensions( b ); 
Object.isExtensible( b ); // returns false
b.text = "Submit"; // OK, you can still edit
delete b.text; // OK too
b.toolTip = "Mine"; // FAIL silently
Button.prototype.toolTip = "Mine"; // OK, only object is prevents extentions not Button class

Hashtable nature of Assets

Figure - JavaScript properties are like key-value pair

JavaScript properties could be declared using "index" notation, "key" notation and "dot" notion. All are useful constructs in different context. See example below:

function Button(text) {
    this[0] = text; 
    this["is enabled"] = true; 
    this.focused = false; 
}

var b1 = new Button("My Button");

b1[0]; // return "My Button". Mostly used in loops
b1["is enabled"]; // return true. Mostly used for space separated, hypen'ed properties
b1.focused; // good ol dot notation return false

that

Figure - 'that' is a way to give 'this' to nested functions

In JavaScript, private methods can not access privilaged assets. Following will not work:

function Button(text) {
     
     this.text = text; // privilaged member
     
     function isEmpty() {return this.text === ""; } // ERROR, this is not available in private methods
}   

To provide necessary access, JavaScript community uses a work around using a var 'that'.

function Button(text) {
     this.text = text;
     var that = this; // store this in private var 'that'
     function isEmpty() {return that.text === ""; } // 'that' will work as it is a private member
}

A more complete example might be:

function Button(text) {
     
     this.text = text;
     
     var that = this;
     
     function isEmpty() {return that.text === ""; }
     
     this.getText = function() { return isEmpty() ? "NO TEXT" : this.text; };
}
     
var b1 = new Button("");     
     
b1.getText(); // return "NO TEXT"     

ASI - Automatic Semi Insertion

Figure - You can write most of JavaScript without semi

JavaScript treats 'every line' as a new statement except for few cases. What this means, you don't have to add semi at the end of every line as JavaScript automatically do this job. This is called ASI or Automatic Semi Insertion. So following is a perfectly valid script:

function Button(text) {
     
     this.text = text
     
     var that = this
     
     function isEmpty() {return that.text === "" }
     
     this.getText = function() { return isEmpty() ? "NO TEXT" : this.text }
}
     
var b1 = new Button("")   
     
b1.getText() // return "NO TEXT"     
For return, throw, break, or continue JavaScript automatically inserts semi for new line.
// ASI if line ends with 'return'
function sum(a,b) { return // ASI here return;
a+b }

sum(1,3) // return undefined
// ASI if line ends with 'throw'
throw // ASI here throw;
"an error" 
// ASI if line ends with 'break'
var day=0

switch (day)
{
case 0:
  x = "Sunday"
  break // ASI here
case 1:
  x = "Monday"
  break
case 2:
  x = "Tuesday"
  break
case 3:
  x = "Wednesday"
  break
case 4:
  x = "Thursday"
  break
case 5:
  x = "Friday"
  break
case 6:
  x = "Saturday"
  break
}

alert(x) // return "Sunday"
// ASI if line ends with 'continue'
continue // ASI here continue;
Following are the places where JavaScript treats a new line as a continuation of previous one, so JavaScript do not auto insert semi for these cases:
// No ASI for unclosed paren
function onclick(
e) 
// No ASI for unclosed array literal
var states = [
"NY", "MA", "CA"] 
// No ASI for unclosed object literal
var states = {
name : "Newyork", code : "MA"} 
// No ASI if ends with comma
var states,
cities 
// No ASI if ends with dot
from("state").
where("id='MA'").
select()
// No ASI if ends with ++ or --
var i = 1, j=5
i
++
j
// here i = 1 and j = 6
// No ASI for 'for'
for(var i = 0; i < 2; i++)
alert("hello") // part of loop
alert("world") // not a part of loop
// No ASI for 'while'
var i = 0;
while(i++ < 2)
alert("hello") // part of loop
alert("world") // not a part of loop
// No ASI for 'do'
var i = 0;
do
alert("hello") // part of loop, to put 2 or more statements use {}
while (i++ < 2)
// No ASI for 'if'
var i = 0
if(i == 0)
alert("hello") // alert will popup
// No ASI for 'else'
var i = 1;
if(i == 0)
alert("hello") 
else
alert("world") // alert will popup

Objects without a class

Figure - Objects without Type

JavaScript is one the language in which you can create objects without class. The simplest of them is an 'empty' object i.e. one that does not have any assets. You can add assets in an empty object anytime or you can declare object with assets. {} in JavaScript represents an empty object or empty object literal.

// empty object
var b={};

Now add some properties:

// object with properties
var b={text:"My Button", visible:false};
b.text; // return "My Button"

And add a method:

// object with method
var b = {text:"My Button", visible:false, show: function() {this.visible = true;} };

b.show();  
b.visible; // returns true

You can return an object from function using object literal notation:

// a function returning object 
function getButton() {
    return {
        text: "My Button",
        visible: false,
        show: function () {
            this.visible = true;
        }
    }
}

getButton().text; // return "My Button"

You can nest objects as well:

// nested objects
var toolbar = {
    button1: {text: "My Button 1"}
   ,button2: {text: "My Button 2"}
}

toolbar.button2.text; // return "My Button 2"

Namespace - Avoiding Name Collision

As you can expect your script will be running with other scripts, therefore it is important to keep your code in a namespace. So far, we have wrote all our classes in a global scope. Let's create few namespaces.

// create namespace. assign already created 'com' object else where or empty object {}
var com = com || {};
com.Acme = com.Acme || {};
com.Acme.UI = com.Acme.UI || {};
com.Acme.UI.Button = com.Acme.UI.Button || {};

Now we have com.Acme.UI namespace ready and Button class added, its time to add class assets. But first note that you can not create constructor function Button() in a global namespace. So checkout some interesting things you can do with anonymous function.

// an anonymous function declaration
function () {}

The above will fail as:

  1. JavaScript does not expect an anonymous function.
  2. JavaScript expects both left and right hand sides of a statement.

On a different note, the simplest form of JavaScript statement is:

// a semi 
;

Let's surround anonymous function with parentheses to make it a statement.

// a function statement
(function () {});

Let's get back to our Button class.

// adding paren to make it a 'function statement'
com.Acme.UI.Button = (function () {});

If we add parentheses at the end of the anonymous function, it will execute immediately.

// adding () to immidiately execute anonymous function
com.Acme.UI.Button = (function () {}());

Now we have anonymous 'container' that will hold our class. Let's add bells and whistles.

// split one liner anonymous container in multi-line
com.Acme.UI.Button = (function () {

}());

// add constructor
com.Acme.UI.Button = (function () {
    function Button(text) {
       
    }
}());

// export Button class (simply return Button)
com.Acme.UI.Button = (function () {
    function Button(text) {
      
    }
    
    return Button;
}());

// add public property
com.Acme.UI.Button = (function () {
    function Button(text) {
       this.text = text;
    }
    
    return Button;
}());

// add public, private and privileged assets
com.Acme.UI.Button = (function () {

    // constructor
    function Button(text) {
        this.text = text; // public property
        var that = this;

        // private method
        function isEmpty() {
            return that.text === "";
        }

        // privileged method
        this.getText = function () {
            return isEmpty() ? "NO TEXT" : this.text;
        };
    }

    // public method
    Button.prototype.resetText = function () {
        return this.text = "";
    }

    return Button;
}());

var b = new com.Acme.UI.Button("My Button");
b.getText(); // return "My Button"
b.resetText();
b.getText(); // "return "NO TEXT"

Library or Module

You can create a JavaScript library that spanning on multiple files using an 'anonymous container' used in previous section. Library or Module provides a scope where you can have both public and private members.

var LIBRARY = (function () {
    // all global variables will be available here
    // however assets in this scope will not conflict 
    // with global scope as they are private
});

var MODULE = (function (jQuery, underscore) {
    // import libraries with different name here
    // to avoid any conflicts. Access to imported
    // variable will be faster as compared to 
    // global access
}($, _));

We can create simple Util library as shown below.

var Util = (function (u) {
    // private 
    var key = "secret";

    // private method
    function hash() {
        return 123;
    }

    // public property
    u.version = "1.0";

    // public method
    u.productName = function () {
        return "Acme Library";
    }

    return u;
}(Util || {}));

Util.productName(); // return "Acme Library"

Following is another way to hide private state and export public methods. Note that an object is returned when anonymous function is invoked.

var Counter = (function () {
    var privateCounter = 0;

    function changeBy(val) {
        privateCounter += val;
    }
    
    return {
        increment: function () {
            changeBy(1);
        },
        decrement: function () {
            changeBy(-1);
        },
        value: function () {
            return privateCounter;
        }
    }
})();

Counter.increment();

alert(Counter.value()); // return 1

Chaining Methods

Chaining methods enable you to call methods on an object one after the other. If you are not returning anything from method return this.

var obj = {
    value: 1,
    increment: function () {
        this.value += 1;
        return this;
    },
    add: function (v) {
        this.value += v;
        return this;
    },
    shout: function () {
        console.log(this.value);
    }
};

// chain method calls
obj.increment().add(3).shout(); // 5

// As opposed to calling them one by one
obj.increment();
obj.add(3);
obj.shout();

Clean getter and setter

JavaScript provides a clean syntax for property get and set method through get and set.

var carStero = {
    _volume: 0,

    get volume() {
        return this._volume;
    },

    set volume(value) {
        if (value < 0 || value > 100) {
            throw new Error("Volume shold be between 0-100");
        }

        this._volume = value;
    }
};

try {
    carStero.volume = 110;
} catch (err) {
    alert(err.message);
}

Globals

Figure - Minimize the use of Globals space

You can declare global variable very easily:

var width = 100; // global
height = 50; // global without var

delete width; // ERROR
delete height; // OK

var states = ["CA", "NY", "MA"];
delete states[1]; // OK, delete NY
states[1]; // return undefined
states.length; // return 3

When the delete operator removes an array element, that element is no longer in the array and accessing it returns undefined. However it is still addressable.

Any member without var goes to global scope.

height; // global

function Button(text) {
  var label = caption = text; // 'label' is private but without var 'caption' is global

  caption = text; // without var 'caption' is global
}

ECMAScript 5 Strict Mode

John Resig has provided an excellent explanation of ES5 a strict mode. Here is what he has to say:

Figure - strict mode basically helps in reducing code writing errors
"use strict";

In strict mode, deleting a variable, a function, or an argument will result in an error.

var foo = "test";

function test() {}

delete foo; // Error 
delete test; // Error 

function test2(arg) {
    delete arg; // Error 
}

Defining a property or function argument more than once in an object literal will cause an exception to be thrown.

// ERROR
{
    foo: true,
    foo: false
}

function (foo, foo) {} //ERROR

Virtually any attempt to use the name 'eval' is prohibited - as is the ability to assign the eval function to a variable or a property of an object.

// All generate ERROR
obj.eval=... 
new Function("eval") 

Additionally, attempts to introduce new variables through an eval will be blocked.

eval("var a=false;"); 
print( typeof a ); // undefined

Finally, a long-standing (and very annoying) bug has been resolved: Cases where null or undefined is coerced into becoming the global object. Strict mode now prevents this from happening and throws an exception instead.

(function(){ ... }).call( null ); // Exception

with(){} statements are dead when strict mode is enabled - in fact it even appears as a syntax error.

Function arguments

There is an arguments object that is available only within a function body. This might be useful in creating multiple class constructors or utility function which loop all arguments to perform some task e.g. sort.

function sort() {
    alert(arguments.length);
    
    arguments[1] = 5; // 1, 5, 3 
    
    alert(arguments[1]);
} 
sort(7,2,3);
sort("A","B","C", "D");

Closure

With nested JavaScript functions comes the ability of Closure i.e. retaining variables on stack even after function is returned. In a normal circumstances, when a function is returned, its stack is destroyed as so is all variable. For a typical function as soon as it returns to calling environment, all its local variables and arguments become eligible for garbage collection.

A closure occurs when a local variable of a function or function argument are kept alive even after the function has returned. Consider following function that returns an anonymous function. The anonymous inner function remembers what the value of min was when it was returned, even though inner function is called later in the code.

function volumeFactory(min) {
    return function (value) {
        return value + min;
    }
}

var mode = "meeting";
var funcSetVolume;

if (mode === "meeting") {
    funcSetVolume = volumeFactory(10);
} else {
    funcSetVolume = volumeFactory(50);
}

alert(funcSetVolume(1)); // min has a clousure, so min=10 and min + 1 = 11

A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created. I haven't mentioned but namespace, library, and module discussed earlier are all examples of closure. A little more interesting example of closure can be seen here.

JavaScript is an OO Language?

Developers are familiar with the notion of inheritance that a 'Derived class is a kind of Base class'. They know this from their education days and from computer science text books. So they are wired to think that class Car extends Vehicle {} and class Truck extends Vehicle {} is a quick OO implementation of parent-child or is a kind of relationship with Vehicle as base class of Car and Truck.

When such developers try OO in JavaScript they realize that beside parent or child there are friends. The relationship between two friends is to ask for help from other friends if you don't know how to do it by yourself! So in a way, JavaScript prototype based chaining is telling that parent are actually friend of their child Smile | :) But this is just an opinion.

Developers are good at thinking and modeling things in parent-child relationship and they do it for two simple reasons beside being taught. A) To better understand code and B) To reuse code. You have seen that JavaScript provide variety of ways to do both of these things, but in a bit different way. Once you get hold of the language, you will love it.

I have just skimmed the surface of what JavaScript has to offer. Hopefully we will see more of its capabilities in later parts of this series.

What's Next

Initially I thought I will cover JavaScript frameworks like Backbone, Angular, Knockout etc. in this part but it seems adequate to leave it for our next discussion and keep this part dedicated to just JavaScript. We will the look into these popular frameworks and see what problems they solve or present.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Syed Rafey Husain
Software Developer (Senior)
Pakistan Pakistan
Software Developer from Karachi, Pakistan.

Comments and Discussions

 
QuestionYet Another Thing PinmemberTariq Newaz Shahriar3-Nov-13 9:31 
AnswerRe: Yet Another Thing PinmemberSyed Rafey Husain9-Nov-13 19:21 
GeneralRe: Yet Another Thing PinmemberTariq Newaz Shahriar23-Nov-13 9:36 
GeneralSuperb Superb Superb PinmemberTariq Newaz Shahriar3-Nov-13 9:24 
GeneralMy vote of 5 PinmemberK. Naveen. Bhat4-Oct-13 3:15 
GeneralMy vote of 5 PinmemberAdam Zuckerman24-Sep-13 8:21 
GeneralRe: My vote of 5 PinmemberSyed Rafey Husain24-Sep-13 19:09 
GeneralMy vote of 4 PinmemberGergo Bogdan24-Sep-13 2:31 
GeneralMy vote of 4 PinprofessionalSankarHarsha24-Sep-13 2:12 
GeneralRe: My vote of 4 PinmemberSyed Rafey Husain24-Sep-13 2:21 
GeneralMy vote of 5 PinprotectorPete O'Hanlon24-Sep-13 1:34 
GeneralRe: My vote of 5 PinmemberSyed Rafey Husain24-Sep-13 2:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 23 Oct 2013
Article Copyright 2013 by Syed Rafey Husain
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid