<commit_before>var findSide = require('./find-side');

// determine the intersection point of a line segment with a line
// original: http://paulbourke.net/geometry/pointlineplane/pdb.c
var EPS = 0.000001;

function segline(x1, y1, x2, y2, x3, y3, x4, y4) {
  var denom  = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
  var numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
  var numerb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);

  // are the line coincident?
  if (Math.abs(numera) < EPS && Math.abs(numerb) < EPS && Math.abs(denom) < EPS) {
    return [
      (x1 + x2) / 2,
      (y1 + y2) / 2
    ];
  }

  // are the line parallel?
  if (Math.abs(denom) < EPS) {
    return; // no intersection
  }

  // is the intersection along the the segment?
  var mua = numera / denom;
  var mub = numerb / denom;

  if ((mua < 0) && (mua > 1) || (mub < 0) || (mub > 1)) {
    return;
  }

  return [
    x1 + (mua) * (x2 - x1),
    y1 + (mua) * (y2 - y1)
  ]
}

function nick (poly, nickingPlanes) {
  poly.splice(0, 0, poly[poly.length - 1]);

  var result = [];
    for (var x = 0; x < poly.length - 1; x++) {
      var lastX = poly[x][0];
      var lastY = poly[x][1];
      var currentX = poly[x + 1][0];
      var currentY = poly[x + 1][1];

      var intersection = segline(nickingPlanes[0], nickingPlanes[1], nickingPlanes[2], nickingPlanes[3], currentX, currentY, lastX, lastY);

      if (Array.isArray(intersection)) {
        result.push([intersection[0], intersection[1]]);
        result.push([intersection[0], intersection[1]]);
      }
      result.push([currentX, currentY]);
    }

  return result;
}

function clip (poly, cuttingPlane) {
  var left = [];
  var right = [];

  var lastPointSide;
  if (!poly || !poly[0]) return {left: undefined, right: undefined};

  // instead of trying to do circular access over the underlying array, just fake it
  // this might not be a great idea later on, if arbitrary precision arithmetic/computer algebra or DAG is used
  //
  //    [1, 2, 3, 4]
  //
  // [4, 1, 2, 3, 4]
  //
  // [4, 1]
  //    [1, 2]
  //       [2, 3]
  //          [3, 4]

  poly.splice(0, 0, poly[poly.length - 1]);

  for (var i = 0; i < poly.length - 1; i++) {
    var lastX = poly[i][0];
    var lastY = poly[i][1];
    var currentX = poly[i + 1][0];
    var currentY = poly[i + 1][1];

    var side = findSide(cuttingPlane[0], cuttingPlane[1], cuttingPlane[2], cuttingPlane[3], currentX, currentY);

    // does the current line segment intersect the cuttingPlane?
    if ((lastPointSide !== 0) && (side !== 0)) {
      var intersection = segline(cuttingPlane[0], cuttingPlane[1], cuttingPlane[2], cuttingPlane[3], currentX, currentY, lastX, lastY);

      if (Array.isArray(intersection)) {
        left.push([intersection[0], intersection[1]]);
        right.push([intersection[0], intersection[1]]);
      }
    }

    if (side < 0) {
      left.push([currentX, currentY]);
    }
    else if (side === 0) {
      left.push([currentX, currentY]);
      right.push([currentX, currentY]);
    }
    else {
      right.push([currentX, currentY]);
    }

    // set lastPointSide for next iteration
    lastPointSide = side;
  }

  return {
    left: left,
    right: right
  }
}

exports.nick = nick;
exports.clip = clip;
<commit_msg>fixed indent inside nick()<commit_after>var findSide = require('./find-side');

// determine the intersection point of a line segment with a line
// original: http://paulbourke.net/geometry/pointlineplane/pdb.c
var EPS = 0.000001;

function segline(x1, y1, x2, y2, x3, y3, x4, y4) {
  var denom  = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
  var numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
  var numerb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);

  // are the line coincident?
  if (Math.abs(numera) < EPS && Math.abs(numerb) < EPS && Math.abs(denom) < EPS) {
    return [
      (x1 + x2) / 2,
      (y1 + y2) / 2
    ];
  }

  // are the line parallel?
  if (Math.abs(denom) < EPS) {
    return; // no intersection
  }

  // is the intersection along the the segment?
  var mua = numera / denom;
  var mub = numerb / denom;

  if ((mua < 0) && (mua > 1) || (mub < 0) || (mub > 1)) {
    return;
  }

  return [
    x1 + (mua) * (x2 - x1),
    y1 + (mua) * (y2 - y1)
  ]
}

function nick (poly, nickingPlanes) {
  poly.splice(0, 0, poly[poly.length - 1]);

  var result = [];
  for (var x = 0; x < poly.length - 1; x++) {
    var lastX = poly[x][0];
    var lastY = poly[x][1];
    var currentX = poly[x + 1][0];
    var currentY = poly[x + 1][1];

    var intersection = segline(nickingPlanes[0], nickingPlanes[1], nickingPlanes[2], nickingPlanes[3], currentX, currentY, lastX, lastY);

    if (Array.isArray(intersection)) {
      result.push([intersection[0], intersection[1]]);
      result.push([intersection[0], intersection[1]]);
    }
    result.push([currentX, currentY]);
  }

  return result;
}

function clip (poly, cuttingPlane) {
  var left = [];
  var right = [];

  var lastPointSide;
  if (!poly || !poly[0]) return {left: undefined, right: undefined};

  // instead of trying to do circular access over the underlying array, just fake it
  // this might not be a great idea later on, if arbitrary precision arithmetic/computer algebra or DAG is used
  //
  //    [1, 2, 3, 4]
  //
  // [4, 1, 2, 3, 4]
  //
  // [4, 1]
  //    [1, 2]
  //       [2, 3]
  //          [3, 4]

  poly.splice(0, 0, poly[poly.length - 1]);

  for (var i = 0; i < poly.length - 1; i++) {
    var lastX = poly[i][0];
    var lastY = poly[i][1];
    var currentX = poly[i + 1][0];
    var currentY = poly[i + 1][1];

    var side = findSide(cuttingPlane[0], cuttingPlane[1], cuttingPlane[2], cuttingPlane[3], currentX, currentY);

    // does the current line segment intersect the cuttingPlane?
    if ((lastPointSide !== 0) && (side !== 0)) {
      var intersection = segline(cuttingPlane[0], cuttingPlane[1], cuttingPlane[2], cuttingPlane[3], currentX, currentY, lastX, lastY);

      if (Array.isArray(intersection)) {
        left.push([intersection[0], intersection[1]]);
        right.push([intersection[0], intersection[1]]);
      }
    }

    if (side < 0) {
      left.push([currentX, currentY]);
    }
    else if (side === 0) {
      left.push([currentX, currentY]);
      right.push([currentX, currentY]);
    }
    else {
      right.push([currentX, currentY]);
    }

    // set lastPointSide for next iteration
    lastPointSide = side;
  }

  return {
    left: left,
    right: right
  }
}

exports.nick = nick;
exports.clip = clip;
<|endoftext|>


<commit_before>
    /**
         * Coal.js
         * Version: 0.1
         * Author: Tomas Holub
         */
        var coal = (function () {

            function Scope() {
                this.$$watchers = [];
                this.$$asyncQueue = [];
            }

            Scope.prototype.$watch = function (watchFn, listenerFn) {
                var watcher = {
                    watchFn: watchFn,
                    listenerFn: listenerFn || function () {
                    }
                };
                this.$$watchers.push(watcher);
            };

            Scope.prototype.$$digestOnce = function () {
                var self = this;
                var dirty;
                for (var i = 0; i < this.$$watchers.length; i++) {
                    var watch = this.$$watchers[i];

                    var newValue = watch.watchFn(self);
                    var oldValue = watch.last;

                    if (newValue !== oldValue) {
                        watch.listenerFn(newValue, oldValue, self);
                        dirty = true;
                        watch.last = newValue;
                    }
                }
                return dirty;
            };

            Scope.prototype.$digest = function () {
                var ttl = 10;
                var dirty;
                do {
                    dirty = this.$$digestOnce();
                    if (dirty && !(ttl--)) {
                        throw "Coal Error: 10 digest iterations reached";
                    }
                } while (dirty);
            }

            function App(element, scope) {
                this.scope = scope;
                this.element = element;

            }

            App.prototype.controller = function (handler) {
                this.scope.$digest();
                this.handler = handler || function () {
                };
                this.$$compile(this.element, this.scope);
            }

            App.prototype.$$compile = function (element, scope) {

                if (typeof element === 'undefined') {
                    var elems = document.getElementsByTagName('*');
                } else {
                    var elems = document.querySelectorAll(element + ' *');
                }
                var events = {
                    INPUT: 'keyup',
                    SELECT: 'change',
                    CHECKBOX: 'change'
                }
                var values = {};
                for (var i = 0; i < elems.length; i++) {

                    if (elems[i].getAttribute("data-co-value") != null) {
                        var name = elems[i].getAttribute("data-co-value");
                        values[name] = elems[i];
                    }
                    if (elems[i].getAttribute("data-co-model") != null) {
                        (function (el, handler) {
                            var model = el.getAttribute("data-co-model");

                            if (el.tagName === 'INPUT' && el.type === 'checkbox') {
                                scope[model] = el.checked;
                            } else {
                                scope[model] = el.value;
                            }
                            scope.$watch(
                                function (scope) {
                                    return scope[model];
                                },
                                function (newValue, oldValue, scope) {
                                    if (typeof values[model] !== 'undefined') {
                                        values[model].innerHTML = newValue;
                                    }
                                    handler(scope, model, newValue, oldValue);
                                }
                            );

                            var event = events[el.tagName];
                            if (el.tagName === 'INPUT' && el.type === 'checkbox') {
                                event = events['CHECKBOX'];
                            }

                            el['on' + event] = function () {
                                if (el.tagName === 'INPUT' && el.type === 'checkbox') {
                                    scope[model] = this.checked;
                                } else {
                                    scope[model] = this.value;
                                }
                                scope.$digest();
                            }

                        }(elems[i], this.handler));
                    }
                }

                // init scope values
                this.scope.$digest();

            }

            function init(element) {
                var scope = new Scope();
                scope.$digest();
                var app   =  new App(element, scope);

                return app;
            }

            return {
                init: init
            }
        }());
<commit_msg>add data-co-click directive<commit_after>        /**
         * Coal.js
         * Version: 0.1
         * Author: Tomas Holub
         */
        var coal = (function () {

            function Scope() {
                this.$$watchers = [];
                this.$$asyncQueue = [];
            }

            Scope.prototype.$watch = function (watchFn, listenerFn) {
                var watcher = {
                    watchFn: watchFn,
                    listenerFn: listenerFn || function () {
                    }
                };
                this.$$watchers.push(watcher);
            };

            Scope.prototype.$$digestOnce = function () {
                var self = this;
                var dirty;
                for (var i = 0; i < this.$$watchers.length; i++) {
                    var watch = this.$$watchers[i];

                    var newValue = watch.watchFn(self);
                    var oldValue = watch.last;

                    if (newValue !== oldValue) {
                        watch.listenerFn(newValue, oldValue, self);
                        dirty = true;
                        watch.last = newValue;
                    }
                }
                return dirty;
            };

            Scope.prototype.$digest = function () {
                var ttl = 10;
                var dirty;
                do {
                    dirty = this.$$digestOnce();
                    if (dirty && !(ttl--)) {
                        throw "Coal Error: 10 digest iterations reached";
                    }
                } while (dirty);
            }

            function App(element, scope) {
                this.scope = scope;
                this.element = element;

            }

            App.prototype.controller = function (handler) {
                this.scope.$digest();
                this.handler = handler || function () {
                };
                this.$$compile(this.element, this.scope);
            }

            App.prototype.$$compile = function (element, scope) {

                if (typeof element === 'undefined') {
                    var elems = document.getElementsByTagName('*');
                } else {
                    var elems = document.querySelectorAll(element + ' *');
                }
                var events = {
                    INPUT: 'keyup',
                    SELECT: 'change',
                    CHECKBOX: 'change'
                }
                var values = {};

                var watchHandler = function(scope,model,handler) {
                    scope.$watch(
                        function (scope) {
                            return scope[model];
                        },
                        function (newValue, oldValue, scope) {
                            if (typeof values[model] !== 'undefined') {
                                values[model].innerHTML = newValue;
                            }
                            handler(scope, model, newValue, oldValue);
                        }
                    );
                }

                for (var i = 0; i < elems.length; i++) {

                    if (elems[i].getAttribute("data-co-value") != null) {
                        var name = elems[i].getAttribute("data-co-value");
                        values[name] = elems[i];
                    }
                    if (elems[i].getAttribute("data-co-model") != null) {
                        (function (el, handler) {
                            var model = el.getAttribute("data-co-model");

                            if (el.tagName === 'INPUT' && el.type === 'checkbox') {
                                scope[model] = el.checked;
                            } else {
                                scope[model] = el.value;
                            }

                            watchHandler(scope,model,handler);

                            var event = events[el.tagName];
                            if (el.tagName === 'INPUT' && el.type === 'checkbox') {
                                event = events['CHECKBOX'];
                            }

                            el['on' + event] = function () {
                                if (el.tagName === 'INPUT' && el.type === 'checkbox') {
                                    scope[model] = this.checked;
                                } else {
                                    scope[model] = this.value;
                                }
                                scope.$digest();
                            }

                        }(elems[i], this.handler));
                    }

                    if (elems[i].getAttribute("data-co-click") != null) {
                        (function(el, handler){
                            var method = el.getAttribute("data-co-click");
                            var FN_ARGS = /^\s*[^\(]*\(\s*([^\)]*)\)/m;
                            var methodName = method.match(/[^(]*/i)[0];
                            var args = method.match(FN_ARGS)[1].replace(/\s+/g,'').split(',');

                            el['onclick'] = function () {
                                if (typeof scope[methodName] === 'function') {
                                    scope[methodName].apply(scope[methodName], args);
                                }
                            }

                        }(elems[i], this.handler))
                    }

                }

                // init scope values
                this.scope.$digest();

            }

            function init(element) {
                var scope = new Scope();
                scope.$digest();
                var app   =  new App(element, scope);

                return app;
            }

            return {
                init: init
            }
        }());
<|endoftext|>


<commit_before>
rect(15, 15, 80, 50);
rect(115, 15, 80, 50);

ellipse(100, 80, 2, 2);
ellipse(105, 80, 2, 2);

line(45, 65, 45, 145);
line(45, 145, 155, 145);
line(155, 145, 165, 65);

fill(0, 0, 0);
ellipse(65, 55, 4, 4);
ellipse(145, 55, 4, 4);<commit_msg>back to just a square<commit_after>
rect(15, 15, 50, 50);
<|endoftext|>


<commit_before>
var target = ""

$("#register").submit(function(){
	register( $( "input:first" ).val());
	return false;
})

$("#kill").submit(function(){
	kill();
	return false;
})

var login = function(){

	info = "request=login&"+$(this).serialize();

    	var user = $(this).serializeArray()[0].value;

	$.ajax({
		type: 'POST',
		url: 'db4free.net',
		data: info,
		success: function(data){
			if (data == "yes"){
				alert("successfully logged in");
			}
			if (data == "no"){
				window.location="login.html";
			}
		},
		error: function(){
			alert('error - probably server hasnt been made yet');

		}
	});

}

var check_register = function(){

	id = device.uuid;

	var info = {request:"check_register", id:id};

	$.ajax({
		type: 'POST',
		url: 'db4free.net',
		data: info,
		success: function(data){
			if (data = "no"){
				window.location="register.html";
			}
		},
		error: function(){
			alert('error - probably server hasnt been made yet');
			window.location="register.html";
		}
	});

}

var register = function(name){

	id = 123;
	//id = device.uuid;

	var info = {request:"register", id:id, name:name};

	$.ajax({
		type: 'POST',
		url: 'db4free.net',
		data: info,
		success: function(data){
			if (data == "yes"){
				alert("registration sucessful");
				window.location="index.html";
			}
			if (data == "no"){
				alert("registration failed");
			}
		},
		error: function(){
			alert('error - probably server hasnt been made yet');
			window.location="index.html";

		}
	});
}

var get_target = function(){

	var info = {request:"get_target", name:name};

	$.ajax({
		type: 'POST',
		url: 'db4free.net',
		data: info,
		success: function(data){
			target = data;
		},
		error: function(){
			alert('error - probably server hasnt been made yet');

		}
	});
}

var kill = function(){

	var latitude;
	var longitude;
	var altitude;

	var GPSonSuccess = function(position) {
		longitude = position.coords.longitude;
		latitude = position.coords.latitude;
		altitude = position.coords.altitude;

	}

	function GPSonError(error) {
    		alert('code: '    + error.code    + '\n' +
          	'message: ' + error.message + '\n');
	}

	navigator.geolocation.getCurrentPosition(GPSonSuccess, GPSonError);

	var info = {request:"kill", latitude:latitude, longitude:longitude, altitude:altitude};

	$.ajax({
		type: 'POST',
		url: 'db4free.net',
		data: info,
		success: function(data){
			alert(data);
		},
		error: function(){
			alert('error - probably server hasnt been made yet');

		}
	});
}
<commit_msg>changed address errors<commit_after>
var target = ""

$("#register").submit(function(){
	register( $( "input:first" ).val());
	return false;
})

$("#kill").submit(function(){
	kill();
	return false;
})

var login = function(){

	info = "request=login&"+$(this).serialize();

    	var user = $(this).serializeArray()[0].value;

	$.ajax({
		type: 'POST',
		url: 'http://db4free.net/3306/',
		data: info,
		success: function(data){
			if (data == "yes"){
				alert("successfully logged in");
			}
			if (data == "no"){
				window.location="login.html";
			}
		},
		error: function(){
			alert('error - probably server hasnt been made yet');

		}
	});

}

var check_register = function(){

	id = device.uuid;

	var info = {request:"check_register", id:id};

	$.ajax({
		type: 'POST',
		url: 'http://db4free.net/3306/',
		data: info,
		success: function(data){
			if (data = "no"){
				window.location="register.html";
			}
		},
		error: function(){
			alert('error - probably server hasnt been made yet');
			window.location="register.html";
		}
	});

}

var register = function(name){

	id = device.uuid;

	var info = {request:"register", id:id, name:name};

	$.ajax({
		type: 'POST',
		url: 'http://db4free.net/3306/',
		data: info,
		success: function(data){
			if (data == "yes"){
				alert("registration sucessful");
				window.location="index.html";
			}
			if (data == "no"){
				alert("registration failed");
			}
		},
		error: function(){
			alert('error - probably server hasnt been made yet');
			window.location="index.html";

		}
	});
}

var get_target = function(){

	var info = {request:"get_target", name:name};

	$.ajax({
		type: 'POST',
		url: 'http://db4free.net/3306/',
		data: info,
		success: function(data){
			target = data;
		},
		error: function(){
			alert('error - probably server hasnt been made yet');

		}
	});
}

var kill = function(){

	var latitude;
	var longitude;
	var altitude;

	var GPSonSuccess = function(position) {
		longitude = position.coords.longitude;
		latitude = position.coords.latitude;
		altitude = position.coords.altitude;

	}

	function GPSonError(error) {
    		alert('code: '    + error.code    + '\n' +
          	'message: ' + error.message + '\n');
	}

	navigator.geolocation.getCurrentPosition(GPSonSuccess, GPSonError);

	var info = {request:"kill", latitude:latitude, longitude:longitude, altitude:altitude};

	$.ajax({
		type: 'POST',
		url: 'http://db4free.net/3306/',
		data: info,
		success: function(data){
			alert(data);
		},
		error: function(){
			alert('error - probably server hasnt been made yet');

		}
	});
}
<|endoftext|>


<commit_before>var contentObject;

function start()
{
    contentObject = document.getElementById( "content" );

    loadIndexContent();
}

function loadIndexContent()
{
    var header = "
Empreendimento Ânima Osasco - Breve Lançamento!
";

    var text = "

";
    text += "
apartamentos de 1 e 2 dormitórios, sendo que os de 2 possuem churrasqueira na varanda
";
    text += "
1 vaga de garagem livre e coberta
";
    text += "
lavanderia coletiva
";
    text += "
Pay Per Use
";
    text += "
lazer completo
";
    text += "
a 300 metros da estação da CPTM
";
    text += "
a partir de R$ 175.900,00
";
    text += "
torre única, com um total de 104 unidades
";
    text += "
2 elevadores
";
    text += "
dimensões do apartamento de 1 dormitório: 30 m²
";
    text += "
dimensões do apartamento de 2 dormitórios: 42 m²
";
    text += "

";

    var contactInfo = "
Contatos:
corretora Lina: linakcorretora@gmail.com
";
    contactInfo += "corretor Edval: edval.corretor@gmail.com
";

    var images = "

";
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"

    contentObject.innerHTML = header + text + contactInfo + images;
}

function loadAquaticaContent()
{
    var header = "
Empreendimento Aquática Osasco - 90% vendido!
";

    var text = "

";
    text += "
disponíveis apartamentos de 1 dormitório (é necessário entrar na fila para os de 2 dormitórios)
";
    text += "
lazer completo
";
    text += "
lavanderia
";
    text += "
Car Wash
";
    text += "
preço do apartamento de 1 dormitório: a partir de R$ 142.900,00
";
    text += "
preço do apartamento de 2 dormitórios: a partir de R$ 179.900,00
";
    text += "
1 vaga de garagem livre e coberta
";
    text += "

";

    var contactInfo = "
Contatos:
corretora Lina: linakcorretora@gmail.com
";
    contactInfo += "corretor Edval: edval.corretor@gmail.com
";

    var images = "

";
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"

    contentObject.innerHTML = header + text + contactInfo + images;
}

function loadContactForm()
{
    contentObject.innerHTML = "Carregando…";
}<commit_msg>Added files via upload<commit_after>var contentObject;

function start()
{
    contentObject = document.getElementById( "content" );

    loadIndexContent();
}

function loadIndexContent()
{
    var header = "
Empreendimento Ânima Osasco - Breve Lançamento!
";

    var text = "

";
    text += "
apartamentos de 1 e 2 dormitórios, sendo que os de 2 possuem churrasqueira na varanda
";
    text += "
1 vaga de garagem livre e coberta
";
    text += "
lavanderia coletiva
";
    text += "
Pay Per Use
";
    text += "
lazer completo
";
    text += "
a 300 metros da estação da CPTM
";
    text += "
a partir de R$ 175.900,00
";
    text += "
torre única, com um total de 104 unidades
";
    text += "
2 elevadores
";
    text += "
dimensões do apartamento de 1 dormitório: 30 m²
";
    text += "
dimensões do apartamento de 2 dormitórios: 42 m²
";
    text += "

";

    var contactInfo = "
Contatos:
corretora Lina: linakcorretora@gmail.com
 (Celular: 11-982459378 (WhatsApp)";
    contactInfo += "corretor Edval: edval.corretor@gmail.com
";

    var images = "

";
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"

    contentObject.innerHTML = header + text + contactInfo + images;
}

function loadAquaticaContent()
{
    var header = "
Empreendimento Aquática Osasco - 90% vendido!
";

    var text = "

";
    text += "
disponíveis apartamentos de 1 dormitório (é necessário entrar na fila para os de 2 dormitórios)
";
    text += "
lazer completo
";
    text += "
lavanderia
";
    text += "
Car Wash
";
    text += "
preço do apartamento de 1 dormitório: a partir de R$ 142.900,00
";
    text += "
preço do apartamento de 2 dormitórios: a partir de R$ 179.900,00
";
    text += "
1 vaga de garagem livre e coberta
";
    text += "

";

    var contactInfo = "
Contatos:
corretora Lina: linakcorretora@gmail.com
 (Celular: 11-982459378 (WhatsApp)";
    contactInfo += "corretor Edval: edval.corretor@gmail.com
";

    var images = "

";
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"
    images += "

"

    contentObject.innerHTML = header + text + contactInfo + images;
}

function loadContactForm()
{
    contentObject.innerHTML = "Carregando…";
}<|endoftext|>


<commit_before>angular.module('dogtalk', ['ngSockethubClient', 'ngSockethubRemoteStorage', 'ngRemoteStorage', 'ngXMPPClient', 'ngMessages']).

/**
 * routes
 */
config(['$routeProvider',
function ($routeProvider) {
  $routeProvider.
    when('/settings', {
      templateUrl: "settings.html",
      controller: "settingsCtrl"
    }).
    when('/', {
      templateUrl: "talk.html",
      controller: "talkCtrl"
    }).
    when('/talk/:address', {
      templateUrl: "talk.html",
      controller: "talkCtrl"
    }).
    otherwise({
      redirectTo: "/"
    });
}]).

/**
 * remotestorage config
 */
run(['RemoteStorageConfig',
function (RScfg) {
  RScfg.modules = [
    ['sockethub', 'rw', {'cache': false}],
    ['messages', 'rw', {'cache': false}],
    ['contacts', 'rw', {'cache': false}]
  ];
}]).

/**
 * check remoteStorage connections
 */
run(['$rootScope', 'RS', '$timeout',
function ($rootScope, RS, $timeout) {
  if (!RS.isConnected()) {
    $timeout(function () {
      if (!RS.isConnected()) {
        $rootScope.$broadcast('message', {message: 'remotestorage-connect', timeout: false});
      }
    }, 1000);
  }
}]).

/**
 * sockethub config & connect
 */
run(['SockethubBootstrap',
function (SockethubBootstrap) {
  SockethubBootstrap.run({
    // default connection settings, if none found in remoteStorage
    host: 'silverbucket.net',
    port: '443',
    path: '/sockethub',
    tls: true,
    secret: '1234567890'
  });
}]).

/**
 * get xmpp config
 */
run(['SH', '$rootScope', 'RS', 'XMPP', 'XMPPSettings',
function (SH, $rootScope, RS, XMPP, settings) {
  RS.call('messages', 'getAccount', ['xmpp', 'default']).then(function (c) {
    console.log('GOT XMPP CONFIG: ', c);
    var cfg = {};

    if (c === undefined) {
      $rootScope.$broadcast('showModalSettingsXmpp', {
        message: 'No existing XMPP configuration information found',
        locked: false
      });
      $rootScope.$broadcast('message', {
        message: 'xmpp-connection',
        type: 'error',
        timeout: false
        //important: true
      });
    } else {
      XMPP.connect(c).then(function () {
        console.log('xmpp connected');
      }, function (err) {
        $rootScope.$broadcast('showModalSettingsXmpp', { message: 'Error connecting via XMPP '+err, locked: false });
        console.log('xmpp ERROR', err);
        $rootScope.$broadcast('message', {
          message: err,
          type: 'error',
          timeout: true
        });
      });
    }

  }, function (err) {
    console.log("RS.call failed: ",err);
  });
}]).

/**
 * emitters
 */

///////////////////////////////////////////////////////////////////////////
//
// CONTROLLERS
//
///////////////////////////////////////////////////////////////////////////

/**
 * controller: appCtrl
 */
controller('appCtrl',
['$scope', '$rootScope', '$route', '$location',
function ($scope, $rootScope, $route, $location) {

  $rootScope.$on("$routeChangeStart", function (event, current, previous, rejection) {
    console.log('routeChangeStart: ', $scope, $rootScope, $route, $location);
  });

  $rootScope.$on("$routeChangeSuccess", function (event, current, previous, rejection) {
    //console.log('routeChangeSuccess: ', $scope, $rootScope, $route, $location);
    console.log('routeChangeSuccess');
  });

  $rootScope.$on("$routeChangeError", function (event, current, previous, rejection) {
    console.log('routeChangeError: ', rejection);
  });

}]).

/**
 * controller: navCtrl
 */
controller("navCtrl",
['$scope', '$route', '$routeParams', '$location',
function ($scope, $route, $routeParams, $location) {
  $scope.navClass = function (page) {
    var currentRoute = $location.path().substring(1) || 'home';
    return page === currentRoute ? 'active' : '';
  };
}]).

/**
 * controller: settingsCtrl
 */
controller("settingsCtrl",
['$scope', '$route', '$routeParams', '$rootScope',
function ($scope, $route, $routeParams, $rootScope) {

  $scope.sockethubSettings = function () {
    $rootScope.$broadcast('showModalSockethubSettings', { locked: false });
  };

  $scope.xmppSettings = function () {
    $rootScope.$broadcast('showModalSettingsXmpp', { locked: false });
  };

  /*
   FIXME: ...
   $scope.$watch('SockethubSettings.connected', function (newVal, oldVal) {
    if (SockethubSettings.connected) {
      SockethubSettings.conn.port = Number(SockethubSettings.conn.port);
      RS.call('sockethub', 'writeConfig', [SockethubSettings.conn]).then(function () {
        console.log("Sockethub config saved to remoteStorage");
      }, function (err) {
        console.log('Failed saving Sockethub config to remoteStorage: ', err);
      });
    }
  });
  */

}]).

/**
 * controller: talkCtrl
 */
controller("talkCtrl",
['$scope', '$route', '$routeParams', '$location', 'XMPP', '$rootScope', 'XMPPSettings',
function ($scope, $route, $routeParams, $location, XMPP, $rootScope, settings) {
  console.log('--- talkCtrl run');

  $scope.model = {
    presence: XMPP.presence.data,
    contacts: XMPP.contacts.data,
    settings: settings,
    requests: XMPP.requests.data
  };

  XMPP.initListener();  // initialize listener for incoming xmpp platform messages

  $scope.model.currentAddress = ($routeParams.address) ? $routeParams.address : 'none';
  $scope.model.currentName = ($scope.model.contacts[$routeParams.address]) ? $scope.model.contacts[$routeParams.address].name : '';
  $scope.model.currentConversation = ($scope.model.contacts[$routeParams.address]) ? $scope.model.contacts[$routeParams.address].conversation : [];

  $scope.$watch('model.contacts', function (newValue, oldValue) {
    console.log('SCOPE WATCH CONTACTS : ', newValue);
  });

  $scope.conversationSwitch = function (address) {
    console.log('---- talkCtrl.conversationSwitch('+address+')');
    if (address !== $routeParams.address) { return ''; }

    if ($scope.model.contacts[address]) {
      $scope.model.currentAddress = address;
      $scope.model.currentName = $scope.model.contacts[address].name;
      $scope.model.currentConversation = $scope.model.contacts[address].conversation;
      console.log('currentConversation: ',$scope.model.currentConversation);
    } else {
      console.log('talkCtrl.conversationSwitch() - not in history');
    }

    return 'active';
  };

  $scope.sendMsg = function (text) {
    $scope.model.saving = true;
    XMPP.sendMsg(settings.conn.actor, $scope.model.currentAddress, text).then(function () {
      $scope.model.sendText = '';
      $scope.model.saving = false;
    }, function (err) {
      console.log('sendMsg error: '+err);
      $scope.model.saving = false;
    });

  };

  $scope.isFromMe = function (address) {
    if (settings.conn.username === address) {
      return true;
    } else {
      return false;
    }
  };

  $scope.acceptBuddyRequest = function (address) {
    $scope.model.saving = true;
    if ($scope.model.requests[address]) {
      console.log('settings;',settings);
      XMPP.requests.accept(settings.conn.actor, address).then(function () {
        $scope.model.saving = false;
        delete $scope.model.requests[address];
        return true;
      }, function (err) {
        $scope.model.saving = false;
        return false;
      });
    } else {
      $scope.model.saving = false;
      return false;
    }
  };

  /*
  $scope.$watch('model.currentAddress', function (address) {
    if (!address) { return false; }

    if ($scope.model.contacts[address]) {
      $scope.model.currentAddress = address;
      $scope.model.currentName = $scope.model.contacts[address].name;
      $scope.model.currentConversation = $scope.model.contacts[address].conversation;
      console.log('WATCH updated: ',$scope.model.current);
    } else {
      console.log('WATCH - not in history');
    }

  });
  */

}]).

/**
 * controller: log
 */
controller("logCtrl",
['$scope', '$route', '$routeParams', '$location',
function ($scope, $route, $routeParams, $location) {
  $scope.model = {
    message: "this is the log page fool!"
  };
}]);

<commit_msg>moved contact list into factory<commit_after>angular.module('dogtalk', ['ngSockethubClient', 'ngSockethubRemoteStorage', 'ngRemoteStorage', 'ngXMPPClient', 'ngMessages']).

/**
 * routes
 */
config(['$routeProvider',
function ($routeProvider) {
  $routeProvider.
    when('/settings', {
      templateUrl: "settings.html",
      controller: "settingsCtrl"
    }).
    when('/', {
      templateUrl: "talk.html",
      controller: "talkCtrl"
    }).
    when('/talk/:address', {
      templateUrl: "talk.html",
      controller: "talkCtrl"
    }).
    otherwise({
      redirectTo: "/"
    });
}]).

/**
 * remotestorage config
 */
run(['RemoteStorageConfig',
function (RScfg) {
  RScfg.modules = [
    ['sockethub', 'rw', {'cache': false}],
    ['messages', 'rw', {'cache': false}],
    ['contacts', 'rw', {'cache': false}]
  ];
}]).

/**
 * check remoteStorage connections
 */
run(['$rootScope', 'RS', '$timeout',
function ($rootScope, RS, $timeout) {
  if (!RS.isConnected()) {
    $timeout(function () {
      if (!RS.isConnected()) {
        $rootScope.$broadcast('message', {message: 'remotestorage-connect', timeout: false});
      }
    }, 1000);
  }
}]).

/**
 * sockethub config & connect
 */
run(['SockethubBootstrap',
function (SockethubBootstrap) {
  SockethubBootstrap.run({
    // default connection settings, if none found in remoteStorage
    host: 'silverbucket.net',
    port: '443',
    path: '/sockethub',
    tls: true,
    secret: '1234567890'
  });
}]).

/**
 * get xmpp config
 */
run(['SH', '$rootScope', 'RS', 'XMPP', 'XMPPSettings',
function (SH, $rootScope, RS, XMPP, settings) {
  RS.call('messages', 'getAccount', ['xmpp', 'default']).then(function (c) {
    console.log('GOT XMPP CONFIG: ', c);
    var cfg = {};

    if (c === undefined) {
      $rootScope.$broadcast('showModalSettingsXmpp', {
        message: 'No existing XMPP configuration information found',
        locked: false
      });
      $rootScope.$broadcast('message', {
        message: 'xmpp-connection',
        type: 'error',
        timeout: false
        //important: true
      });
    } else {
      XMPP.connect(c).then(function () {
        console.log('xmpp connected');
      }, function (err) {
        $rootScope.$broadcast('showModalSettingsXmpp', { message: 'Error connecting via XMPP '+err, locked: false });
        console.log('xmpp ERROR', err);
        $rootScope.$broadcast('message', {
          message: err,
          type: 'error',
          timeout: true
        });
      });
    }

  }, function (err) {
    console.log("RS.call failed: ",err);
  });
}]).

/**
 * emitters
 */

///////////////////////////////////////////////////////////////////////////
//
// CONTROLLERS
//
///////////////////////////////////////////////////////////////////////////

/**
 * controller: appCtrl
 */
controller('appCtrl',
['$scope', '$rootScope', '$route', '$location',
function ($scope, $rootScope, $route, $location) {

  $rootScope.$on("$routeChangeStart", function (event, current, previous, rejection) {
    console.log('routeChangeStart: ', $scope, $rootScope, $route, $location);
  });

  $rootScope.$on("$routeChangeSuccess", function (event, current, previous, rejection) {
    //console.log('routeChangeSuccess: ', $scope, $rootScope, $route, $location);
    console.log('routeChangeSuccess');
  });

  $rootScope.$on("$routeChangeError", function (event, current, previous, rejection) {
    console.log('routeChangeError: ', rejection);
  });

}]).

/**
 * controller: navCtrl
 */
controller("navCtrl",
['$scope', '$route', '$routeParams', '$location',
function ($scope, $route, $routeParams, $location) {
  $scope.navClass = function (page) {
    var currentRoute = $location.path().substring(1) || 'home';
    return page === currentRoute ? 'active' : '';
  };
}]).

/**
 * controller: settingsCtrl
 */
controller("settingsCtrl",
['$scope', '$route', '$routeParams', '$rootScope',
function ($scope, $route, $routeParams, $rootScope) {

  $scope.sockethubSettings = function () {
    $rootScope.$broadcast('showModalSockethubSettings', { locked: false });
  };

  $scope.xmppSettings = function () {
    $rootScope.$broadcast('showModalSettingsXmpp', { locked: false });
  };

  /*
   FIXME: ...
   $scope.$watch('SockethubSettings.connected', function (newVal, oldVal) {
    if (SockethubSettings.connected) {
      SockethubSettings.conn.port = Number(SockethubSettings.conn.port);
      RS.call('sockethub', 'writeConfig', [SockethubSettings.conn]).then(function () {
        console.log("Sockethub config saved to remoteStorage");
      }, function (err) {
        console.log('Failed saving Sockethub config to remoteStorage: ', err);
      });
    }
  });
  */

}]).

/**
 * controller: talkCtrl
 */
controller("talkCtrl",
['$scope', '$route', '$routeParams', '$location', 'XMPP', '$rootScope', 'XMPPSettings',
function ($scope, $route, $routeParams, $location, XMPP, $rootScope, settings) {
  console.log('--- talkCtrl run');

  $scope.model = {
    presence: XMPP.presence.data,
    contacts: XMPP.contacts.data,
    settings: settings,
    requests: XMPP.requests.data
  };

  XMPP.initListener();  // initialize listener for incoming xmpp platform messages

  $scope.model.currentAddress = ($routeParams.address) ? $routeParams.address : 'none';
  $scope.model.currentName = ($scope.model.contacts[$routeParams.address]) ? $scope.model.contacts[$routeParams.address].name : '';
  $scope.model.currentConversation = ($scope.model.contacts[$routeParams.address]) ? $scope.model.contacts[$routeParams.address].conversation : [];

  $scope.$watch('model.contacts', function (newValue, oldValue) {
    console.log('SCOPE WATCH CONTACTS : ', newValue);
  });

  $scope.conversationSwitch = function (address) {
    console.log('---- talkCtrl.conversationSwitch('+address+')');
    if (address !== $routeParams.address) { return ''; }

    if ($scope.model.contacts[address]) {
      $scope.model.currentAddress = address;
      $scope.model.currentName = $scope.model.contacts[address].name;
      $scope.model.currentConversation = $scope.model.contacts[address].conversation;
      console.log('currentConversation: ',$scope.model.currentConversation);
    } else {
      console.log('talkCtrl.conversationSwitch() - not in history');
    }

    return 'active';
  };

  $scope.sendMsg = function (text) {
    $scope.model.saving = true;
    XMPP.sendMsg(settings.conn.actor, $scope.model.currentAddress, text).then(function () {
      $scope.model.sendText = '';
      $scope.model.saving = false;
    }, function (err) {
      console.log('sendMsg error: '+err);
      $scope.model.saving = false;
    });

  };

  $scope.isFromMe = function (address) {
    if (settings.conn.username === address) {
      return true;
    } else {
      return false;
    }
  };

  $scope.acceptBuddyRequest = function (address) {
    $scope.model.saving = true;
    if ($scope.model.requests[address]) {
      console.log('settings;',settings);
      XMPP.requests.accept(settings.conn.actor, address).then(function () {
        $scope.model.saving = false;
        delete $scope.model.requests[address];
        return true;
      }, function (err) {
        $scope.model.saving = false;
        return false;
      });
    } else {
      $scope.model.saving = false;
      return false;
    }
  };

  /*
  $scope.$watch('model.currentAddress', function (address) {
    if (!address) { return false; }

    if ($scope.model.contacts[address]) {
      $scope.model.currentAddress = address;
      $scope.model.currentName = $scope.model.contacts[address].name;
      $scope.model.currentConversation = $scope.model.contacts[address].conversation;
      console.log('WATCH updated: ',$scope.model.current);
    } else {
      console.log('WATCH - not in history');
    }

  });
  */

}]).

/**
 * controller: log
 */
controller("logCtrl",
['$scope', '$route', '$routeParams', '$location',
function ($scope, $route, $routeParams, $location) {
  $scope.model = {
    message: "this is the log page fool!"
  };
}]);

<|endoftext|>


<commit_before>(function () {
	"use strict";

	var CONFIG = {
		serverUid : "http",
		serverGid : "http",
		listenIPv4 : true,
		listenIPv6 : true,
		servicePort : 37320,
		workersKeepIdle : 7200,	// Unit: second
		workersTimeout : 60,	// Unit: second
		messageCap : 1024 * 16	// Unit: octet
	},

	Messenger = function (salt, type, payload) {
		var messageTypeRegex = /^(?:header|body|end)$/;

		this.salt = salt;
		this.type = messageTypeRegex.test(type) === true ? type : "unknown";
		this.payload = payload;
	},
	RequestHeaderMessenger = function (salt, invoking, req) {
		Messenger.call(this, salt, "header", {
			invoking : invoking,
			params : req.params
		});
	},
	ResponseHeaderMessenger = function (salt, headers) {
		Messenger.call(this, salt, "header", {
			statusCode : 200,
			headers : headers
		});
	},

	NodePool = function () {},

	cluster = require("cluster");

	NodePool.prototype.balancer = function () {
		var server = require("./scgi.js").createServer(),

		url = require("url"),

		idleWorker = function () {
			this.isIdle = true;
			this.stopIdling = setTimeout(this.kill.bind(this), CONFIG.workersKeepIdle * 1000);
		},

		invokeWorker = function (path) {
			var worker = null;

			for (let workerId in cluster.workers) {
				if (cluster.workers[workerId].workFor === path && cluster.workers[workerId].isIdle === true) {
					worker = cluster.workers[workerId];
					clearTimeout(cluster.workers[workerId].stopIdling);
					break;
				}
			}

			if (worker === null) {
				worker = cluster.fork();
				worker.workFor = path;
				worker.idle = idleWorker;
			}

			worker.isIdle = false;

			return worker;
		},

		timeoutResponse = function () {
			this.res.setStatus(408);
			this.res.flushHeaders(true);
			this.res.end();
			this.worker.kill();
		},

		workerMessageReceptor = function (workerMes) {
			var res = this.res, worker = this.worker;

			if (workerMes.salt !== this.salt) {
				return;
			}

			switch (workerMes.type) {
				case "header":
					if (! isNaN(workerMes.payload.statusCode)) {
						res.setStatus(workerMes.payload.statusCode);
					}

					workerMes.payload.headers.forEach(function (header) {
						res.setHeader(header);
					});

					res.flushHeaders();

					break;

				case "body":
					res.write(new Buffer(workerMes.payload));
					break;

				case "end":
					res.end();
					worker.removeListener("message", this.workerMessageReceiver);
					worker.idle();
					break;

				default:
					break;
			}
		},

		onReqData = function (bChunk) {
			var messageContainer = new Messenger(this.salt, "body", null), p = 0;

			while (p < bChunk.length) {
				messageContainer.payload = bChunk.slice(
					p,
					p = p + CONFIG.messageCap < bChunk.length ? p + CONFIG.messageCap : bChunk.length
				);
				this.worker.send(messageContainer);
			}
		},

		onReqEnd = function () {
			this.worker.send(new Messenger(this.salt, "end"));
			this.worker.on("message", this.workerMessageReceiver);
		},

		onResClose = function () {
			this.worker.kill();
		},

		responder = function (req, res) {
			var salt = Math.random(),
			requested = url.parse(req.params.SCRIPT_FILENAME.replace(/^[^:]*:scgi:/, "scgi:")),
			invoking = url.parse(requested.pathname).pathname,

			worker = invokeWorker(invoking),

			resources = {
				salt : salt,
				res : res,
				worker : worker
			};

			resources.workerMessageReceiver = workerMessageReceptor.bind(resources);

			worker.send(new RequestHeaderMessenger(salt, invoking, req));

			req.on("data", onReqData.bind(resources));
			req.on("end", onReqEnd.bind(resources));
			res.on("close", onResClose.bind(resources));

			req.setTimeout(CONFIG.workersTimeout * 1000, timeoutResponse.bind(resources));
		};

		CONFIG.listenIPv4 && server.listen(CONFIG.servicePort, "0.0.0.0");
		CONFIG.listenIPv6 && server.listen(CONFIG.servicePort, "::");

		server.on("request", responder);
	};

	NodePool.prototype.worker = function () {
		var built = null, request = null,

		fs = require("fs"),

		genInstanceInterface = function (request) {
			var ret = {},

			salt = request.salt,

			responseStatus = NaN,
			responseHeaders = [],
			isHeaderSent = false,

			bCache = {
				chunks : [],
				cachedLength : 0
			},

			flushHeaders = function () {
				var messageContainer = new ResponseHeaderMessenger(salt, responseHeaders);

				if(! isNaN(responseStatus)) {
					messageContainer.statusCode = responseStatus;
				}

				process.send(messageContainer);
				isHeaderSent = true;
			};

			ret.request = {
				params : request.header.params,
				body : Buffer.concat(request.body.chunks, request.body.length)
			};

			ret.setStatus = function (sCode, reasonPhrase) {
				responseStatus = parseInt(sCode, 10);

				if (reasonPhrase !== undefined) {
					responseHeaders.push(["Status:", sCode.toString(), reasonPhrase].join(" "));
				}
			};

			ret.setHeader = function (expr) {
				responseHeaders.push(expr);
			};

			ret.flush = function () {
				var messageContainer = new Messenger(salt, "body", null),
				bChunk = typeof bCache.chunks[0] === "string" ? bCache.chunks.join("") : Buffer.concat(bCache.chunks, bCache.chachedLength);

				isHeaderSent === false && flushHeaders();

				for (let p = 0; p < bChunk.length;) {
					messageContainer.payload = bChunk.slice(
						p,
						p = p + CONFIG.messageCap < bChunk.length ? p + CONFIG.messageCap : bChunk.length
					);
					process.send(messageContainer);
				}

				bCache.chunks = [];
				bCache.cachedLength = 0;
			};

			ret.echo = function(data) {
				var toBeCached = null;

				if (data === undefined || data === null || data.length === 0) {
					return;
				}

				if (Buffer.isBuffer(data) === true) {
					if (bCache.length > 0 && Buffer.isBuffer(bCache.chunks[0]) !== true) {
						ret.flush();
					}

					toBeCached = data;
				} else {
					if (bCache.length > 0 && typeof bCache.chunks[0] !== typeof "") {
						ret.flush();
					}

					toBeCached = typeof data === typeof "" ? data : data.toString();
				}

				if (bCache.cachedLength + toBeCached.length > CONFIG.messageCap) {
					ret.flush();
				}

				bCache.chunks.push(toBeCached);
				bCache.cachedLength += toBeCached.length;

				if (toBeCached.length > CONFIG.messageCap) {
					ret.flush();
				}
			};

			ret.end = function () {
				isHeaderSent === false && flushHeaders();
				ret.flush();
				process.send(new Messenger(salt, "end"));
			};

			return ret;
		},

		respondBalancerRequest = function (request) {
			var instanceInterface = genInstanceInterface(request);

			try {
				process.chdir(require("path").dirname(fs.realpathSync(request.header.invoking)));

				if (built === null || fs.statSync(request.header.invoking).ctime.getTime() > built.builtAt.getTime()) {
					delete require.cache[fs.realpathSync(request.header.invoking)];
					built = require(request.header.invoking);
					built.builtAt = new Date();
				}

				instanceInterface.setHeader("Content-Type: text/html; charset=UTF-8");
				built.exec(instanceInterface);
			} catch (e) {
				instanceInterface.setStatus(500);
				instanceInterface.end();
				cluster.worker.kill();
			}
		},

		balancerMessageReceptor = function (messenger) {
			switch (messenger.type) {
				case "header":
					request = {
						salt : messenger.salt,
						header : messenger.payload,
						body : {
							length : 0,
							chunks : []
						}
					};
					break;

				case "body":
					if (messenger.salt === request.salt) {
						let newBodyChunk = new Buffer(messenger.payload);

						request.body.chunks.push(newBodyChunk);
						request.body.length += newBodyChunk.length;
					}
					break;

				case "end":
					respondBalancerRequest(request);
					break;
				default:
					break;
			}
		};

		process.on("message", balancerMessageReceptor);
	};

	process.setuid(CONFIG.serverUid) && process.setgid(CONFIG.serverGid);

	if (cluster.isMaster === true) {
		new NodePool().balancer();
	} else if (cluster.isWorker === true) {
		new NodePool().worker();
	}
})();
<commit_msg>[core] Fixed bug which fails to specify HTTP response status<commit_after>(function () {
	"use strict";

	var CONFIG = {
		serverUid : "http",
		serverGid : "http",
		listenIPv4 : true,
		listenIPv6 : true,
		servicePort : 37320,
		workersKeepIdle : 7200,	// Unit: second
		workersTimeout : 60,	// Unit: second
		messageCap : 1024 * 16	// Unit: octet
	},

	Messenger = function (salt, type, payload) {
		var messageTypeRegex = /^(?:header|body|end)$/;

		this.salt = salt;
		this.type = messageTypeRegex.test(type) === true ? type : "unknown";
		this.payload = payload;
	},
	RequestHeaderMessenger = function (salt, invoking, req) {
		Messenger.call(this, salt, "header", {
			invoking : invoking,
			params : req.params
		});
	},
	ResponseHeaderMessenger = function (salt, headers) {
		Messenger.call(this, salt, "header", {
			statusCode : 200,
			headers : headers
		});
	},

	NodePool = function () {},

	cluster = require("cluster");

	NodePool.prototype.balancer = function () {
		var server = require("./scgi.js").createServer(),

		url = require("url"),

		idleWorker = function () {
			this.isIdle = true;
			this.stopIdling = setTimeout(this.kill.bind(this), CONFIG.workersKeepIdle * 1000);
		},

		invokeWorker = function (path) {
			var worker = null;

			for (let workerId in cluster.workers) {
				if (cluster.workers[workerId].workFor === path && cluster.workers[workerId].isIdle === true) {
					worker = cluster.workers[workerId];
					clearTimeout(cluster.workers[workerId].stopIdling);
					break;
				}
			}

			if (worker === null) {
				worker = cluster.fork();
				worker.workFor = path;
				worker.idle = idleWorker;
			}

			worker.isIdle = false;

			return worker;
		},

		timeoutResponse = function () {
			this.res.setStatus(408);
			this.res.flushHeaders(true);
			this.res.end();
			this.worker.kill();
		},

		workerMessageReceptor = function (workerMes) {
			var res = this.res, worker = this.worker;

			if (workerMes.salt !== this.salt) {
				return;
			}

			switch (workerMes.type) {
				case "header":
					if (! isNaN(workerMes.payload.statusCode)) {
						res.setStatus(workerMes.payload.statusCode);
					}

					workerMes.payload.headers.forEach(function (header) {
						res.setHeader(header);
					});

					res.flushHeaders();

					break;

				case "body":
					res.write(new Buffer(workerMes.payload));
					break;

				case "end":
					res.end();
					worker.removeListener("message", this.workerMessageReceiver);
					worker.idle();
					break;

				default:
					break;
			}
		},

		onReqData = function (bChunk) {
			var messageContainer = new Messenger(this.salt, "body", null), p = 0;

			while (p < bChunk.length) {
				messageContainer.payload = bChunk.slice(
					p,
					p = p + CONFIG.messageCap < bChunk.length ? p + CONFIG.messageCap : bChunk.length
				);
				this.worker.send(messageContainer);
			}
		},

		onReqEnd = function () {
			this.worker.send(new Messenger(this.salt, "end"));
			this.worker.on("message", this.workerMessageReceiver);
		},

		onResClose = function () {
			this.worker.kill();
		},

		responder = function (req, res) {
			var salt = Math.random(),
			requested = url.parse(req.params.SCRIPT_FILENAME.replace(/^[^:]*:scgi:/, "scgi:")),
			invoking = url.parse(requested.pathname).pathname,

			worker = invokeWorker(invoking),

			resources = {
				salt : salt,
				res : res,
				worker : worker
			};

			resources.workerMessageReceiver = workerMessageReceptor.bind(resources);

			worker.send(new RequestHeaderMessenger(salt, invoking, req));

			req.on("data", onReqData.bind(resources));
			req.on("end", onReqEnd.bind(resources));
			res.on("close", onResClose.bind(resources));

			req.setTimeout(CONFIG.workersTimeout * 1000, timeoutResponse.bind(resources));
		};

		CONFIG.listenIPv4 && server.listen(CONFIG.servicePort, "0.0.0.0");
		CONFIG.listenIPv6 && server.listen(CONFIG.servicePort, "::");

		server.on("request", responder);
	};

	NodePool.prototype.worker = function () {
		var built = null, request = null,

		fs = require("fs"),

		genInstanceInterface = function (request) {
			var ret = {},

			salt = request.salt,

			responseStatus = NaN,
			responseHeaders = [],
			isHeaderSent = false,

			bCache = {
				chunks : [],
				cachedLength : 0
			},

			flushHeaders = function () {
				var messageContainer = new ResponseHeaderMessenger(salt, responseHeaders);

				if(! isNaN(responseStatus)) {
					messageContainer.payload.statusCode = responseStatus;
				}

				process.send(messageContainer);
				isHeaderSent = true;
			};

			ret.request = {
				params : request.header.params,
				body : Buffer.concat(request.body.chunks, request.body.length)
			};

			ret.setStatus = function (sCode, reasonPhrase) {
				responseStatus = parseInt(sCode, 10);

				if (reasonPhrase !== undefined) {
					responseHeaders.push(["Status:", sCode.toString(), reasonPhrase].join(" "));
				}
			};

			ret.setHeader = function (expr) {
				responseHeaders.push(expr);
			};

			ret.flush = function () {
				var messageContainer = new Messenger(salt, "body", null),
				bChunk = typeof bCache.chunks[0] === "string" ? bCache.chunks.join("") : Buffer.concat(bCache.chunks, bCache.chachedLength);

				isHeaderSent === false && flushHeaders();

				for (let p = 0; p < bChunk.length;) {
					messageContainer.payload = bChunk.slice(
						p,
						p = p + CONFIG.messageCap < bChunk.length ? p + CONFIG.messageCap : bChunk.length
					);
					process.send(messageContainer);
				}

				bCache.chunks = [];
				bCache.cachedLength = 0;
			};

			ret.echo = function(data) {
				var toBeCached = null;

				if (data === undefined || data === null || data.length === 0) {
					return;
				}

				if (Buffer.isBuffer(data) === true) {
					if (bCache.length > 0 && Buffer.isBuffer(bCache.chunks[0]) !== true) {
						ret.flush();
					}

					toBeCached = data;
				} else {
					if (bCache.length > 0 && typeof bCache.chunks[0] !== typeof "") {
						ret.flush();
					}

					toBeCached = typeof data === typeof "" ? data : data.toString();
				}

				if (bCache.cachedLength + toBeCached.length > CONFIG.messageCap) {
					ret.flush();
				}

				bCache.chunks.push(toBeCached);
				bCache.cachedLength += toBeCached.length;

				if (toBeCached.length > CONFIG.messageCap) {
					ret.flush();
				}
			};

			ret.end = function () {
				isHeaderSent === false && flushHeaders();
				ret.flush();
				process.send(new Messenger(salt, "end"));
			};

			return ret;
		},

		respondBalancerRequest = function (request) {
			var instanceInterface = genInstanceInterface(request);

			try {
				process.chdir(require("path").dirname(fs.realpathSync(request.header.invoking)));

				if (built === null || fs.statSync(request.header.invoking).ctime.getTime() > built.builtAt.getTime()) {
					delete require.cache[fs.realpathSync(request.header.invoking)];
					built = require(request.header.invoking);
					built.builtAt = new Date();
				}

				instanceInterface.setHeader("Content-Type: text/html; charset=UTF-8");
				built.exec(instanceInterface);
			} catch (e) {
				instanceInterface.setStatus(500);
				instanceInterface.end();
				cluster.worker.kill();
			}
		},

		balancerMessageReceptor = function (messenger) {
			switch (messenger.type) {
				case "header":
					request = {
						salt : messenger.salt,
						header : messenger.payload,
						body : {
							length : 0,
							chunks : []
						}
					};
					break;

				case "body":
					if (messenger.salt === request.salt) {
						let newBodyChunk = new Buffer(messenger.payload);

						request.body.chunks.push(newBodyChunk);
						request.body.length += newBodyChunk.length;
					}
					break;

				case "end":
					respondBalancerRequest(request);
					break;
				default:
					break;
			}
		};

		process.on("message", balancerMessageReceptor);
	};

	process.setuid(CONFIG.serverUid) && process.setgid(CONFIG.serverGid);

	if (cluster.isMaster === true) {
		new NodePool().balancer();
	} else if (cluster.isWorker === true) {
		new NodePool().worker();
	}
})();
<|endoftext|>


<commit_before>'use strict';

define([
  'angular',
  'text!camunda-tasklist-ui/process/start.html',
  'camunda-tasklist-ui/api',
  'angular-bootstrap'
], function(
  angular,
  templateStartForm
) {

  var processModule = angular.module('cam.tasklist.process', [
    'cam.tasklist.client',
    'ui.bootstrap'
  ]);

  processModule.controller('processStartModalFormCtrl', [
    '$rootScope',
    '$scope',
    '$q',
    '$translate',
    'camAPI',
    'CamForm',
    'Notifications',
  function(
    $rootScope,
    $scope,
    $q,
    $translate,
    camAPI,
    CamForm,
    Notifications
  ) {
    var $ = angular.element;

    function errorNotification(src, err) {
      $translate(src).then(function(translated) {
        Notifications.addError({
          status: translated,
          message: (err ? err.message : '')
        });
      });
    }

    function successNotification(src) {
      $translate(src).then(function(translated) {
        Notifications.addMessage({
          duration: 3000,
          status: translated
        });
      });
    }

    var ProcessDefinition = camAPI.resource('process-definition');

    var emptyVariable = {
      name:   '',
      value:  '',
      type:   ''
    };

    // http://docs.camunda.org/latest/api-references/rest/#process-definition-start-process-instance-method
    // Valid variable values are Boolean, Number, String and Date values.
    // NOTE: Actually... forget the docs...
    var variableTypes = {
      'Boolean':  'checkbox',
      'Integer':  'text',
      'Double':   'text',
      'Long':     'text',
      'Short':    'text',
      'String':   'text',
      'Date':     'datetime'
    };

    function close(result) {
      var isFunction = angular.isFunction($scope.$close);

      var cb =  isFunction ?
                $scope.$close :
                angular.noop;

      cb(result);
    }

    // used by the pagination directive
    $scope.currentPage = 1;

    $scope.itemsPerPage = 25;

    $scope.totalProcesses = 0;

    $scope.processes = [];

    $scope.variables = [];

    $scope.variableTypes = variableTypes;

    $scope.loadingProcesses = false;

    $scope.close = close;

    $scope.selected = function($item) {
      $scope.getStartForm($item);
    };

    $scope.lookupProcess = function(val) {
      var deferred = $q.defer();

      $scope.loadingProcesses = true;

      ProcessDefinition.list({
        nameLike: '%'+ val +'%'
      }, function(err, res) {
        $scope.loadingProcesses = false;

        if (err) {
          return deferred.reject(err);
        }

        deferred.resolve(res.items);
      });

      return deferred.promise;
    };

    $scope.showList = function() {
      $scope.startingProcess = null;
    };

    $scope.loadProcesses = function() {
      $scope.loadingProcesses = true;
      var where = {};

      // I found that in the REST API documentation,
      // I supposed it was aimed to be used,
      // but using it lead to empty results
      // where.startableBy = camStorage.get('user').id;

      where.maxResults = where.maxResults || $scope.itemsPerPage;

      ProcessDefinition.list(where, function(err, res) {
        $scope.loadingProcesses = false;
        if (err) {
          Notifications.addError(err);
          throw err;
        }

        $scope.totalProcesses = res.count;

        $scope.processes = res.items.sort(function(a, b) {
          var aName = (a.name || a.key).toLowerCase();
          var bName = (b.name || b.key).toLowerCase();
          if (aName < bName)
             return -1;
          if (aName > bName)
            return 1;
          return 0;
        });
      });
    };
    $scope.loadProcesses();

    $scope.getStartForm = function(startingProcess) {
      $scope.startingProcess = startingProcess;
      $scope.loadingProcesses = true;

      ProcessDefinition.startForm({
        id: startingProcess.id
      }, function(err, result) {
        $scope.loadingProcesses = false;

        if (err) {
          Notifications.addError(err);
          throw err;
        }

        // stop here if there is no "embedded form"
        if (!result.key) { return; }

        var parts = result.key.split('embedded:');
        var ctx = result.contextPath;
        var formUrl;

        if (parts.length > 1) {
          formUrl = parts.pop();
          // ensure a trailing slash
          ctx = ctx + (ctx.slice(-1) !== '/' ? '/' : '');
          // formUrl = formUrl[0] === '/' ? formUrl.slice(1) : formUrl;
          formUrl = formUrl.replace(/app:(\/?)/, ctx);
        }
        else {
          formUrl = result.key;
        }

        var form = new CamForm({
          processDefinitionId:  startingProcess.id,
          containerElement:     $('.start-form-container'),
          client:               camAPI,
          formUrl:              formUrl
        });

        $scope.startingProcess._form = form;
      });
    };

    $scope.addVariable = function() {
      $scope.variables.push(angular.copy(emptyVariable));
    };
    // $scope.addVariable();

    $scope.removeVariable = function(delta) {
      var vars = [];

      angular.forEach($scope.variables, function(variable, d) {
        if (d != delta) {
          vars.push(variable);
        }
      });

      $scope.variables = vars;
    };

    $scope.submitForm = function() {
      if (!$scope.startingProcess || !$scope.startingProcess.key) {
        return false;
      }

      function submitCb(err, res) {
        if (err) {
          errorNotification('PROCESS_START_ERROR', err);
          throw err;
        }

        successNotification('PROCESS_START_OK');
        $rootScope.$broadcast('tasklist.process.start');
        close(res);
      }

      if ($scope.startingProcess._form) {
        $scope.startingProcess._form.submit(submitCb);
      }
      else {
        var data = {};
        data.id = $scope.startingProcess.id;
        data.variables = {};
        angular.forEach($scope.variables, function(variable) {
          data.variables[variable.name] = {
            type: variable.type,
            value: variable.value
          };
        });
        ProcessDefinition.submitForm(data, submitCb);
      }
    };
  }]);

  processModule.controller('processStartCtrl', [
          '$modal', '$scope',
  function($modal,   $scope) {
    $scope.openProcessStartModal = function() {
      $modal.open({
        size: 'lg',
        controller: 'processStartModalFormCtrl',
        template: templateStartForm
      });
    };
  }]);

  return processModule;
});
<commit_msg>fix(process start): clear variables<commit_after>'use strict';

define([
  'angular',
  'text!camunda-tasklist-ui/process/start.html',
  'camunda-tasklist-ui/api',
  'angular-bootstrap'
], function(
  angular,
  templateStartForm
) {

  var processModule = angular.module('cam.tasklist.process', [
    'cam.tasklist.client',
    'ui.bootstrap'
  ]);

  processModule.controller('processStartModalFormCtrl', [
    '$rootScope',
    '$scope',
    '$q',
    '$translate',
    'camAPI',
    'CamForm',
    'Notifications',
  function(
    $rootScope,
    $scope,
    $q,
    $translate,
    camAPI,
    CamForm,
    Notifications
  ) {
    var $ = angular.element;

    function errorNotification(src, err) {
      $translate(src).then(function(translated) {
        Notifications.addError({
          status: translated,
          message: (err ? err.message : '')
        });
      });
    }

    function successNotification(src) {
      $translate(src).then(function(translated) {
        Notifications.addMessage({
          duration: 3000,
          status: translated
        });
      });
    }

    var ProcessDefinition = camAPI.resource('process-definition');

    var emptyVariable = {
      name:   '',
      value:  '',
      type:   ''
    };

    // http://docs.camunda.org/latest/api-references/rest/#process-definition-start-process-instance-method
    // Valid variable values are Boolean, Number, String and Date values.
    // NOTE: Actually... forget the docs...
    var variableTypes = {
      'Boolean':  'checkbox',
      'Integer':  'text',
      'Double':   'text',
      'Long':     'text',
      'Short':    'text',
      'String':   'text',
      'Date':     'datetime'
    };

    function close(result) {
      var isFunction = angular.isFunction($scope.$close);

      var cb =  isFunction ?
                $scope.$close :
                angular.noop;

      cb(result);
    }

    // used by the pagination directive
    $scope.currentPage = 1;

    $scope.itemsPerPage = 25;

    $scope.totalProcesses = 0;

    $scope.processes = [];

    $scope.variables = [];

    $scope.variableTypes = variableTypes;

    $scope.loadingProcesses = false;

    $scope.close = close;

    $scope.selected = function($item) {
      $scope.getStartForm($item);
    };

    $scope.lookupProcess = function(val) {
      var deferred = $q.defer();

      $scope.loadingProcesses = true;

      ProcessDefinition.list({
        nameLike: '%'+ val +'%'
      }, function(err, res) {
        $scope.loadingProcesses = false;

        if (err) {
          return deferred.reject(err);
        }

        deferred.resolve(res.items);
      });

      return deferred.promise;
    };

    $scope.showList = function() {
      $scope.startingProcess = null;
      $scope.variables = [];
    };

    $scope.loadProcesses = function() {
      $scope.loadingProcesses = true;
      var where = {};

      // I found that in the REST API documentation,
      // I supposed it was aimed to be used,
      // but using it lead to empty results
      // where.startableBy = camStorage.get('user').id;

      where.maxResults = where.maxResults || $scope.itemsPerPage;

      ProcessDefinition.list(where, function(err, res) {
        $scope.loadingProcesses = false;
        if (err) {
          Notifications.addError(err);
          throw err;
        }

        $scope.totalProcesses = res.count;

        $scope.processes = res.items.sort(function(a, b) {
          var aName = (a.name || a.key).toLowerCase();
          var bName = (b.name || b.key).toLowerCase();
          if (aName < bName)
             return -1;
          if (aName > bName)
            return 1;
          return 0;
        });
      });
    };
    $scope.loadProcesses();

    $scope.getStartForm = function(startingProcess) {
      $scope.startingProcess = startingProcess;
      $scope.loadingProcesses = true;

      ProcessDefinition.startForm({
        id: startingProcess.id
      }, function(err, result) {
        $scope.loadingProcesses = false;

        if (err) {
          Notifications.addError(err);
          throw err;
        }

        // stop here if there is no "embedded form"
        if (!result.key) { return; }

        var parts = result.key.split('embedded:');
        var ctx = result.contextPath;
        var formUrl;

        if (parts.length > 1) {
          formUrl = parts.pop();
          // ensure a trailing slash
          ctx = ctx + (ctx.slice(-1) !== '/' ? '/' : '');
          // formUrl = formUrl[0] === '/' ? formUrl.slice(1) : formUrl;
          formUrl = formUrl.replace(/app:(\/?)/, ctx);
        }
        else {
          formUrl = result.key;
        }

        var form = new CamForm({
          processDefinitionId:  startingProcess.id,
          containerElement:     $('.start-form-container'),
          client:               camAPI,
          formUrl:              formUrl
        });

        $scope.startingProcess._form = form;
      });
    };

    $scope.addVariable = function() {
      $scope.variables.push(angular.copy(emptyVariable));
    };
    // $scope.addVariable();

    $scope.removeVariable = function(delta) {
      var vars = [];

      angular.forEach($scope.variables, function(variable, d) {
        if (d != delta) {
          vars.push(variable);
        }
      });

      $scope.variables = vars;
    };

    $scope.submitForm = function() {
      if (!$scope.startingProcess || !$scope.startingProcess.key) {
        return false;
      }

      function submitCb(err, res) {
        if (err) {
          errorNotification('PROCESS_START_ERROR', err);
          throw err;
        }

        successNotification('PROCESS_START_OK');
        $rootScope.$broadcast('tasklist.process.start');
        close(res);
      }

      if ($scope.startingProcess._form) {
        $scope.startingProcess._form.submit(submitCb);
      }
      else {
        var data = {};
        data.id = $scope.startingProcess.id;
        data.variables = {};
        angular.forEach($scope.variables, function(variable) {
          data.variables[variable.name] = {
            type: variable.type,
            value: variable.value
          };
        });
        ProcessDefinition.submitForm(data, submitCb);
      }
    };
  }]);

  processModule.controller('processStartCtrl', [
          '$modal', '$scope',
  function($modal,   $scope) {
    $scope.openProcessStartModal = function() {
      $modal.open({
        size: 'lg',
        controller: 'processStartModalFormCtrl',
        template: templateStartForm
      });
    };
  }]);

  return processModule;
});
<|endoftext|>


<commit_before>/**
 * Class and function collection based upon WoltLab Community Framework
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 */
var versions = new Array('travianer.de/game.php', 'travians.com/game.php', 'traviani.it/game.php', 'travianer.fr/game.php', 'travianer.net/game.php');
var defaultSettings = {}

/**
 * extend local storage to load default settings
 */
Storage.prototype.getItem = function(key) {
	var value = this[key];
	if(value == undefined) {
		return defaultSettings[key];
	}
	return value;
}

/**
 * Initialize CORE namespace
 */
var CORE = {};

/**
 * Extends jQuery's chainable methods.
 */
$.fn.extend({

	slideFadeIn: function(duration, callback) {
		var height = this.show().css({height:'auto'}).height();
		this.css({height:0}).animate({
			height: height,
			opacity: 1
		}, duration, callback);
	},

	slideFadeOut: function(duration, callback) {
		if(this.is(':hidden')) return;
		this.animate({
			height: 0,
			opacity: 0
		}, duration, function() {
			$(this).hide();
			callback();
		});
	}

});

/**
 * core methods
 */
$.extend(CORE, {

	/**
	 * Counter for dynamic element id's
	 * @var	integer
	 */
	_idCounter: 0,

	/**
	 * initializes language system and hide all elements witch need specific options
	 */
	initPage: function() {
		$('[data-i18n]:not(.i18n-replaced)').each(function() {
			$(this).html(chrome.i18n.getMessage($(this).data('i18n')));
		});
		$('[data-i18n-value]:not(.i18n-replaced)').each(function() {
			$(this).val(chrome.i18n.getMessage($(this).data('i18n-value')));
		});
		$('[data-i18n-title]:not(.i18n-replaced)').each(function() {
			$(this).attr('title', chrome.i18n.getMessage($(this).data('i18n-title')));
		});
		$('[data-required-storage]').each(function() {
			var itemName = $(this).data('requiredStorage');

		});
	},

	/**
	 * Returns a dynamically created id.
	 * @see		https://github.com/sstephenson/prototype/blob/master/src/prototype/dom/dom.js#L1789
	 * @return	string
	 */
	getRandomID: function() {
		var $elementID = '';

		do {
			$elementID = 'travitools' + this._idCounter++;
		} while($.wcfIsset($elementID));

		return $elementID;
	},

	/**
	 * Wrapper for $.inArray which returns boolean value instead of index value, similar to PHP's in_array().
	 * @param	mixed		needle
	 * @param	array		haystack
	 * @return	boolean
	 */
	inArray: function(needle, haystack) {
		return ($.inArray(needle, haystack) != -1);
	}

});

/**
 * Simple implementation for collapsible content.
 */
CORE.Collapsible = {

	/**
	 * Initializes collapsibles.
	 */
	init: function() {
		$('.jsCollapsible').each($.proxy(function(index, button) {
			this._initButton(button);
		}, this));
	},

	/**
	 * Binds an event listener on all buttons triggering the collapsible.
	 * @param	object		button
	 */
	_initButton: function(button) {
		var $button = $(button);
		var $isOpen = $button.data('isOpen');
		if(!$isOpen) {
			$('#' + $button.data('collapsibleContainer')).hide();
		}
		$button.click($.proxy(this._toggle, this));
	},

	/**
	 * Toggles collapsible containers on click.
	 * @param	object		event
	 */
	_toggle: function(event) {
		var $button = $(event.currentTarget);
		var $isOpen = $button.data('isOpen');
		var $target = $('#' + $button.data('collapsibleContainer').replace(/(:|\.)/g, '\\$1'));

		if($isOpen) {
			$target.stop().slideFadeOut(200, $.proxy(function() {
				this._toggleImage($button, 'arrowRight');
			}, this));
			$isOpen = false;
		} else {
			$target.stop().slideFadeIn(200, $.proxy(function() {
				this._toggleImage($button, 'arrowDown');
			}, this));
			$isOpen = true;
		}

		$button.data('isOpen', $isOpen);

		// suppress event
		event.stopPropagation();
		return false;
	},

	/**
	 * Toggles image of target button.
	 * @param	jQuery		button
	 * @param	string		image
	 */
	_toggleImage: function(button, image) {
		button.attr('src', '../images/'+ image +'.svg');
	}

}<commit_msg>add traviansTab function and reorder code<commit_after>/**
 * Class and function collection based upon WoltLab Community Framework
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 */

/**
 * extend local storage to load default settings
 */
var defaultSettings = {}
Storage.prototype.getItem = function(key) {
	var value = this[key];
	if(value == undefined) {
		return defaultSettings[key];
	}
	return value;
}

/**
 * Initialize CORE namespace
 */
var CORE = {};

/**
 * Extends jQuery's chainable methods.
 */
$.fn.extend({

	slideFadeIn: function(duration, callback) {
		var height = this.show().css({height:'auto'}).height();
		this.css({height:0}).animate({
			height: height,
			opacity: 1
		}, duration, callback);
	},

	slideFadeOut: function(duration, callback) {
		if(this.is(':hidden')) return;
		this.animate({
			height: 0,
			opacity: 0
		}, duration, function() {
			$(this).hide();
			callback();
		});
	}

});

/**
 * core methods
 */
$.extend(CORE, {

	/**
	 * Counter for dynamic element id's
	 * @var	integer
	 */
	_idCounter: 0,

	_versions: new Array('travianer.de/game.php', 'travians.com/game.php', 'traviani.it/game.php', 'travianer.fr/game.php', 'travianer.net/game.php'),

	/**
	 * Returns a dynamically created id.
	 * @see		https://github.com/sstephenson/prototype/blob/master/src/prototype/dom/dom.js#L1789
	 * @return	string
	 */
	getRandomID: function() {
		var $elementID = '';

		do {
			$elementID = 'travitools' + this._idCounter++;
		} while($.wcfIsset($elementID));

		return $elementID;
	},

	/**
	 * Wrapper for $.inArray which returns boolean value instead of index value, similar to PHP's in_array().
	 * @param	mixed		needle
	 * @param	array		haystack
	 * @return	boolean
	 */
	inArray: function(needle, haystack) {
		return ($.inArray(needle, haystack) != -1);
	},

	/**
	 * initializes language system and hide all elements witch need specific options
	 */
	initPage: function() {
		$('[data-i18n]:not(.i18n-replaced)').each(function() {
			$(this).html(chrome.i18n.getMessage($(this).data('i18n')));
		});
		$('[data-i18n-value]:not(.i18n-replaced)').each(function() {
			$(this).val(chrome.i18n.getMessage($(this).data('i18n-value')));
		});
		$('[data-i18n-title]:not(.i18n-replaced)').each(function() {
			$(this).attr('title', chrome.i18n.getMessage($(this).data('i18n-title')));
		});
	},

	/**
	 * inject content script (e.g. for attendance control)
	 * @param	tabID		integer		defaults to the active tab of the current window
	 */
	injectContentScript: function(tabID) {
		if(tabID == undefined) tabID = null;
		chrome.tabs.executeScript(tabID, {file:'contentscript.js'});
	},

	/**
	 * check if given tab match versions pattern
	 */
	traviansTab: function(tab) {
		if(tab.url == undefined) return false;
		$.each(this._versions, function(index, pattern) {
			if(tab.url.indexOf(pattern) != -1) return true;
		});
		return false;
	}

});

/**
 * Simple implementation for collapsible content.
 */
CORE.Collapsible = {

	/**
	 * Initializes collapsibles.
	 */
	init: function() {
		$('.jsCollapsible').each($.proxy(function(index, button) {
			this._initButton(button);
		}, this));
	},

	/**
	 * Binds an event listener on all buttons triggering the collapsible.
	 * @param	object		button
	 */
	_initButton: function(button) {
		var $button = $(button);
		var $isOpen = $button.data('isOpen');
		if(!$isOpen) {
			$('#' + $button.data('collapsibleContainer')).hide();
		}
		$button.click($.proxy(this._toggle, this));
	},

	/**
	 * Toggles collapsible containers on click.
	 * @param	object		event
	 */
	_toggle: function(event) {
		var $button = $(event.currentTarget);
		var $isOpen = $button.data('isOpen');
		var $target = $('#' + $button.data('collapsibleContainer').replace(/(:|\.)/g, '\\$1'));

		if($isOpen) {
			$target.stop().slideFadeOut(200, $.proxy(function() {
				this._toggleImage($button, 'arrowRight');
			}, this));
			$isOpen = false;
		} else {
			$target.stop().slideFadeIn(200, $.proxy(function() {
				this._toggleImage($button, 'arrowDown');
			}, this));
			$isOpen = true;
		}

		$button.data('isOpen', $isOpen);

		// suppress event
		event.stopPropagation();
		return false;
	},

	/**
	 * Toggles image of target button.
	 * @param	jQuery		button
	 * @param	string		image
	 */
	_toggleImage: function(button, image) {
		button.attr('src', '../images/'+ image +'.svg');
	}

}<|endoftext|>