function Shape(){
this.name = 'Shape';
this.toString = function () {
    return this.name;
  };
}

function TwoDShape(){
  this.name = '2D shape';
}

function Triangle(side, height){
  this.name = 'Triangle';
  this.side = side;
  this.height = height;
  this.getArea = function () {
    return this.side * this.height / 2;
  };
}
---
// konstruktor
function Shape() {}

// rozszerzanie prototypu
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.name;
};

// kolejny konstruktor
function TwoDShape() {}

// dziedziczenie
TwoDShape.prototype = new Shape();
TwoDShape.prototype.constructor = TwoDShape;

// rozszerzanie prototypu
TwoDShape.prototype.name = '2D shape';
---

function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
// dziedziczenie
Triangle.prototype = new TwoDShape();
Triangle.prototype.constructor = Triangle;

// rozszerzanie prototypu
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
  return this.side * this.height / 2;
};

---

function Shape() {}
// rozszerzenie prototypu
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function() {
  return this.name;
};

function TwoDShape() {}
// obsługa dziedziczenia
TwoDShape.prototype = Shape.prototype;
TwoDShape.prototype.constructor = TwoDShape;
// rozszerzenie prototypu
TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) { 
  this.side = side;
  this.height = height;
}

// obsługa dziedziczenia
Triangle.prototype = TwoDShape.prototype;
Triangle.prototype.constructor = Triangle;
// rozszerzenie prototypu
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
  return this.side * this.height / 2;
}

---

function Shape() {}
// rozszerzenie prototypu
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function() {
return this.name;
};

function TwoDShape() {}
// obsługa dziedziczenia
var F = function(){};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
// rozszerzenie prototypu
TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) { 
  this.side = side;
  this.height = height;
}

// obsługa dziedziczenia
var F = function(){};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
// rozszerzenie prototypu
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function() {
return this.side * this.height / 2;
};
---

function Shape() {}
// rozszerzenie prototypu
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
var const = this.constructor;
returnconst.uber
    ? this.const.uber.toString() + ', ' + this.name
    : this.name;
};

function TwoDShape() {}
// obsługa dziedziczenia
var F = function () {};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.uber = Shape.prototype;
// rozszerzenie prototypu
TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) {
this.side = side;
this.height = height;
}

// obsługa dziedziczenia
var F = function () {};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
Triangle.uber = TwoDShape.prototype;
// rozszerzenie prototypu
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
return this.side * this.height / 2;
};

---

function extend(Child, Parent) {
  var F = function(){};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;
}

---

// funkcja pomocnicza dla dziedziczenia
function extend(Child, Parent) {
  var F = function () {};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;
}

// definiowanie -> rozszerzanie
function Shape() {}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.constructor.uber
    ? this.constructor.uber.toString() + ', ' + this.name
    : this.name;
};

// definiowanie -> dziedziczenie -> rozszerzanie
function TwoDShape() {}
extend(TwoDShape, Shape);
TwoDShape.prototype.name = '2D shape';

// definiowanie
function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
// dziedziczenie
extend(Triangle, TwoDShape);
// rozszerzanie
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
  return this.side * this.height / 2;
};

---

function extend2(Child, Parent) { 
  var p = Parent.prototype;
  var c = Child.prototype;
  for (var i in p) { 
    c[i] = p[i];
  }
  c.uber = p;
}
---

var Shape = function () {};
var TwoDShape = function () {};
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.uber
    ? this.uber.toString() + ', ' + this.name
    : this.name;
};

---

function extendCopy(p) { 
  var c = {};
  for (var i in p) {
    c[i] = p[i];
  }
  c.uber = p;
  return c;
}

---

var Shape = { 
  name: 'Shape',
  toString: function() {
    return this.name;
  }
};

---

var twoDee = extendCopy(Shape);
twoDee.name = '2D shape;
twoDee.toString = function() {
return this.uber.toString() + ', ' + this.name;
};

---

var triangle = extendCopy(twoDee);
triangle.name = 'Triangle';
triangle.getArea = function() {
return this.side * this.height / 2;
};

---

function deepCopy(p, c) {
  var c = c || {};
  for (var i in p) { 
    if (p.hasOwnProperty(i)) {
      if (typeof p[i] === 'object') {
        c[i] = Array.isArray(p[i]) ? [] : {};
        deepCopy(p[i], c[i]);
      } else {
        c[i] = p[i];
      }
    }
  }  
  return c;
}

---

var parent = {
  numbers: [1, 2, 3],
  letters: ['a', 'b', 'c'],
  obj: {
    prop: 1
  },
  bool: true
};

---

if (Array.isArray !== "function") {
  Array.isArray = function (candidate) {
  return
    Object.prototype.toString.call(candidate) ===
    '[object Array]';
  };
}

---

function object(o) {
  var n;
  function F() {}
  F.prototype = o;
  n = new F();
  n.uber = o;
  return n;
}

---

function objectPlus(o, stuff) {
  var n;
  function F() {}
  F.prototype = o;
  n = new F();
  n.uber = o;
  for (var i in stuff) {
     n[i] = dodatki[i];
  }
  return n;
}

---

var shape = {
  name: 'shape',
  toString: function() {
    return this.name;
  }
};

---

var twoDee = objectPlus(shape, {
  name: '2D shape',
  toString: function () {
    return this.uber.toString() + ', ' + this.name;
  }
});

---

var triangle = objectPlus(twoDee, {
  name: 'Triangle',
  getArea: function() {return this.side * this.height / 2;
},
  side: 0,
  height: 0
});

---

function multi() {
  var n = {}, stuff, j = 0, len = arguments.length;
  for (j = 0; j < len; j++) { 
    stuff = arguments[j];
    for (var i in stuff) {
      if (stuff.hasOwnProperty(i)) { 
        n[i] = stuff[i];
      }
    }
  } 
  return n;

---

var shape = {
  name: 'Shape',
  toString: function() {
    return this.name;
  }
};

var twoDee = {
  name: '2D shape',
  dimensions: 2
};

var triangle = multi(shape, twoDee, {
  name: 'Triangle',
  getArea: function() {
    return this.side * this.height / 2;
  },
  side: 5,
  height: 10
});

---

function triangle(s, h) { 
  var that = object(twoD);
  that.name = 'Triangle';
  that.getArea = function() {
    return this.side * this.height / 2;
  };
  that.side = s;
  that.height = h;
  return that;
}

----

function Shape(id) {
  this.id = id;
}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function() {
  return this.name;
};

---

function Triangle() {
  Shape.apply(this, arguments);
}
Triangle.prototype = new Shape();
Triangle.prototype.name = 'Triangle';

---

function Shape(id) {
  this.id = id;
}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function() {
  return this.name;
};

function Triangle() {
  Shape.apply(this, arguments);
}
extend2(Triangle, Shape);
Triangle.prototype.name = 'Triangle';

---

function Point(x, y) {
  this.x = x;
  this.y = y;
}

---

function Line(p1, p2) { 
  this.p1 = p1;
  this.p2 = p2;
  this.length = Math.sqrt(
    Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)
  );
}

---

function Shape() {
  this.points = [];
  this.lines  = [];
  this.init();
}

---

Shape.prototype = {
  // ustawienie wskaźnika na konstruktor
  constructor: Shape,

  // inicjowanie, ustawia wskaźnik this.context na obiekt canvas
  init: function() {
    if (typeof this.context === 'undefined') {
      var canvas = document.getElementById('canvas');
      Shape.prototype.context = canvas.getContext('2d');
    } 
  },

  // metoda rysująca figurę za pomocą pętli przechodzącej przez this.points
  draw: function() {
    var i, ctx = this.context;
    ctx.strokeStyle = this.getColor();
    ctx.beginPath();
    ctx.moveTo(this.points[0].x, this.points[0].y);
    for(i = 1; i < this.points.length; i++) {
      ctx.lineTo(this.points[i].x, this.points[i].y);
    }
    ctx.closePath();
    ctx.stroke();
  },

  // metoda generująca losowy kolor
  getColor: function() {
    var i, rgb = [];
    for (i = 0; i < 3; i++) {
      rgb[i] = Math.round(255 * Math.random());
    }
    return 'rgb(' + rgb.join(',') + ')';
  },

  // metoda, która przechodzi przez tablicę punktów,
  // tworzy instancje Line i dodaje je do this.lines
  getLines: function() {
    if (this.lines.length > 0) {
      return this.lines;
    }
    var i, lines = [];
    for(i = 0; i < this.points.length; i++) {
      lines[i] = new Line(this.points[i], 
      this.points[i+1]) || this.points[0]);
    }
    this.lines = lines;
    return lines;
  },

  // metoda obliczająca pole powierzchni, implementowana przez poszczególne dzieci
  getArea: function(){},
  // metoda obliczająca obwód poprzez sumowanie długości wszystkich boków (linii)
  getPerimeter: function(){
    var i, perim = 0, lines = this.getLines();
    for (i = 0; i < lines.length; i++) {
      perim += lines[i].length;
    }
    return perim;
  }
};

---

function Triangle(a, b, c){
  this.points = [a, b, c];
  this.getArea = function() {   
    var p = this.getPerimeter();
    s = p / 2;
    return Math.sqrt(s * (s - this.lines[0].length) * 
      (s - this.lines[1].length) * (s - this.lines[2].length));
  };
}

---

function Rectangle(p, side_a, side_b){
  this.points = [
    p,
    new Point(p.x + side_a, p.y),           // prawy górny róg
    new Point(p.x + side_a, p.y + side_b),  // prawy dolny róg
    new Point(p.x, p.y + side_b)            // lewy dolny róg
  ];
  this.getArea = function() {
  return side_a * side_b;
  };
}

---

