<commit_before>var should = require("should");
var blpopPool = require("../index").RedisBlpopPool;
var sinon = require("sinon");
var Redis = require("ioredis");
require("should-sinon");

// @todo Using real redis, because fakeredis cannot handle it
var redis = new Redis({
    port: 6379,
    host: "192.168.15.10"
});

function random(min, max){
    return Math.floor(Math.random() * (max - min)) + min;
}

function randomKey(){
    return "test:" + random(0,100) + ":" + new Date().getTime().toString().substr(-4) + ":" + random(0,100);
}

describe("Testing pool", function(){
    beforeEach(function(done){
        redis.flushdb(function(){
            done();
        })
    });

    it("Should throw exception while creating without redis connection", function(){
        (function(){new blpopPool()}).should.throw();
    });

    it("Should create pool with default options", function(){
        var pool = new blpopPool(redis);

        (pool._options).should.have.properties(["maxClients", "clientOptions"]);
        (pool._options.clientOptions).should.have.properties(["maxKeys", "timeout"]);
    });

    it("Should create new client when key is registered", function(){
        var pool = new blpopPool(redis);

        (pool._clients).should.be.empty();

        pool.registerKey("test", function(err, msg){});

        (pool._clients).should.not.be.empty();
    });

    it ("Should create new client when one client's keys spaces are out", function(){
        var pool = new blpopPool(redis, {
            maxClients: 0,
            clientOptions: {
                maxKeys: 2
            }
        });

        pool.registerKey(randomKey(), function(err, msg){});
        (pool._clients.length).should.equal(1);
        pool.registerKey(randomKey(), function(err, msg){});
        (pool._clients.length).should.equal(1);

        pool.registerKey(randomKey(), function(err, msg){});
        (pool._clients.length).should.equal(2);
    });

    it ("Should throw error when maximum clients reached", function(){
        var pool = new blpopPool(redis, {
            maxClients: 2,
            clientOptions: {
                maxKeys: 2
            }
        });

        for (var i=0;i<4;i++){
            pool.registerKey(randomKey(), function(err, msg){});
        }

        (function(){ pool.registerKey(randomKey(), function(err, msg){}) }).should.throw();
    });

    it ("Should remove key from client", function(){
        var pool = new blpopPool(redis);

        var key = randomKey();

        pool.registerKey(randomKey(), function(err, msg){});
        pool.registerKey(key, function(err, msg){});

        (pool._clients[0]._keys.length).should.equal(2);
        (pool._clients[0]._callbacks.length).should.equal(2);

        pool.removeKey(key);

        (pool._clients[0]._keys.length).should.equal(1);
        (pool._clients[0]._callbacks.length).should.equal(1);
    });

    it ("Should add key to client with empty spaces", function(){
        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 2
            }
        });

        var key = randomKey();

        // Create 3 clients each with 2 keys
        for (var i=0;i<5;i++){
            pool.registerKey(randomKey(), function(err, msg){});
            // Add key in the middle (...)
            if (i === 2){
                pool.registerKey(key, function(err, msg){});
            }
        }

        (pool._clients.length).should.equal(3);

        (pool._clients[0]._keys.length).should.equal(2);
        (pool._clients[1]._keys.length).should.equal(2);
        (pool._clients[2]._keys.length).should.equal(2);

        // remove one key from the client
        pool.removeKey(key);

        (pool._clients[1]._keys.length).should.equal(1);

        // Add key to the pool
        pool.registerKey(randomKey(), function(err, msg){});

        (pool._clients.length).should.equal(3);

        (pool._clients[0]._keys.length).should.equal(2);
        (pool._clients[1]._keys.length).should.equal(2);
        (pool._clients[2]._keys.length).should.equal(2);
    });

    // Todo Handle duplicate keys?
});

describe("Testing pool client", function(){
    beforeEach(function(done){
        redis.flushdb(function(){
            done();
        })
    });

    it("Should add key and callback if space available", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient();

        (client._keys.length).should.equal(0);
        (client._callbacks.length).should.equal(0);

        client.addKey("test", function(err, msg){});

        (client._keys.length).should.equal(1);
        (client._callbacks.length).should.equal(1);
    });

    it("Should not add key and callback if out of space", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient({maxKeys: 2});

        (client._keys.length).should.equal(0);
        (client._callbacks.length).should.equal(0);

        for (var i=0;i<3;i++){
            client.addKey(randomKey(), function(err, msg){});
        }

        (client._keys.length).should.equal(2);
        (client._callbacks.length).should.equal(2);
    });

    it ("Should remove key", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient();

        client.addKey("test", function(err, msg){});

        (client._keys.length).should.equal(1);
        (client._callbacks.length).should.equal(1);

        client.removeKey("test");

        (client._keys.length).should.equal(0);
        (client._callbacks.length).should.equal(0);
    });

    it ("Should rotate keys and callbacks - first to last", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient();

        var keys = [];
        var callbacks = [];

        for (var i=0;i<3;i++){
            callbacks.push(function(err, msg){return i;});
            keys.push(randomKey());

            client.addKey(keys[i], callbacks[i]);
        }

        (client._keys[0]).should.equal(keys[0]);
        (client._callbacks[0]).should.equal(callbacks[0]);

        client.rotateKeys();

        (client._keys[0]).should.equal(keys[1]);
        (client._callbacks[0]).should.equal(callbacks[1]);

        (client._keys[2]).should.equal(keys[0]);
        (client._callbacks[2]).should.equal(callbacks[0]);
    });

    it ("Should rotate keys and callbacks - any position to last", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient();

        var keys = [];
        var callbacks = [];

        for (var i=0;i<3;i++){
            callbacks.push(function(err, msg){return i});
            keys.push(randomKey());

            client.addKey(keys[i], callbacks[i]);
        }

        (client._keys[0]).should.equal(keys[0]);
        (client._callbacks[0]).should.equal(callbacks[0]);

        client.rotateKeys(1);

        (client._keys[0]).should.equal(keys[0]);
        (client._callbacks[0]).should.equal(callbacks[0]);

        (client._keys[1]).should.equal(keys[2]);
        (client._callbacks[1]).should.equal(callbacks[2]);

        (client._keys[2]).should.equal(keys[1]);
        (client._callbacks[2]).should.equal(callbacks[1]);
    });

    it ("Should call right callback on receiving message", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        for (var i=0;i<4;i++){
            pool.registerKey(randomKey(), function(err, msg){});
        }

        var callback = sinon.spy();
        var key = randomKey();

        pool.registerKey(key, callback);

        pool._clients[0].rotateKeys();
        pool._clients[0].rotateKeys();

        setTimeout(function(){
            redis.lpush(key, "a");

            setTimeout(function(){
                callback.should.be.calledOnce();
                done();
            }, 100);
        }, 2000);
    });

    it ("Should do key rotation on blpop callback", function(done){
        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var key = randomKey();

        pool.registerKey(key, function(err, msg){});

        setTimeout(function(){
            pool._clients[0].rotateKeys = sinon.spy();
            redis.lpush(key, "a");

            setTimeout(function () {
                pool._clients[0].rotateKeys.should.be.calledOnce();
                done();
            }, 500);
        },500);
    });

    it ("Should rotate key that received message at the end of the queue", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var key = randomKey();

        for (var i=0;i<5;i++){
            pool.registerKey(randomKey(), function(err, msg){});

            if (i === 2){
                pool.registerKey(key, function(err, msg){});
            }
        }

        setTimeout(function(){
            redis.lpush(key, "a");

            setTimeout(function(){
                should(pool._clients[0]._keys[pool._clients[0]._keys.length-1]).equal(key);
                done();
            }, 100);
        }, 2000);
    });

    it ("Should rotate keys correctly on timing out", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var key = randomKey();

        pool.registerKey(key, function(err, msg){});

        for (var i=0;i<5;i++){
            pool.registerKey(randomKey(), function(err, msg){});
        }

        setTimeout(function(){
            should(pool._clients[0]._keys[pool._clients[0]._keys.length-1]).equal(key);
            done();
        }, 2000);
    });

    it ("Should listen to all keys after timeout/new message", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var callback = sinon.spy();
        var key = randomKey();

        pool.registerKey(randomKey(), function(err, msg){});
        pool.registerKey(key, callback);

        callback.should.not.be.called();

        setTimeout(function(){
            redis.lpush(key, "a");

            setTimeout(function(){
                callback.should.be.calledOnce();
                done();
            }, 100);
        }, 2000);
    });

    it ("Should restart blpop after receiving message", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        pool.registerKey(randomKey(), function(err, msg){});

        pool._clients[0].startBlpop = sinon.spy();

        setTimeout(function(){
            redis.lpush(randomKey(), "a");

            setTimeout(function () {
                pool._clients[0].startBlpop.should.be.calledOnce();
                done();
            }, 100);
        },2000);
    });

    it ("Should restart blpop after timing out", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        pool.registerKey(randomKey(), function(err, msg){});

        pool._clients[0].startBlpop = sinon.spy();

        setTimeout(function(){
            pool._clients[0].startBlpop.should.be.calledOnce();
            done();
        },2000);
    });

    it ("Should increment message count on receiving message", function(done){
        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var key = randomKey();

        pool.registerKey(key, function(err, msg){});

        (pool._clients[0].messageCount).should.equal(0);

        setTimeout(function(){
            redis.lpush(key, "a");
            setTimeout(function(){
                (pool._clients[0].messageCount).should.equal(1);
                done();
            }, 100);
        },100);
    });

    it ("Should not increment message count on timing out", function(done){
        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        pool.registerKey(randomKey(), function(err, msg){});

        (pool._clients[0].messageCount).should.equal(0);

        setTimeout(function(){
            (pool._clients[0].messageCount).should.equal(0);
            done();
        },1500);
    });

    // @todo finish testcase
    it ("Should log warning when receiving message for unknown key", function(){
        // true.should.be.false();
    });

    // @todo finish testcase
    it ("Should throw error if received redis error and have no callback", function(){
        // true.should.be.false();
    });

    it ("Should not start blpop if there are no keys in the queue", function(done){
        var pool = new blpopPool(redis);

        var client = pool.createClient({timeout: 1});

        client.onMessage = sinon.spy();

        client.startBlpop();

        setTimeout(function(){
            client.onMessage.should.not.be.called();
            done();
        }, 1500);
    });
});
<commit_msg>Unfortunately travis-ci cannot handle real redis... so we are stuck with testing<commit_after>var should = require("should");
var blpopPool = require("../index").RedisBlpopPool;
var sinon = require("sinon");
var Redis = require("ioredis");
require("should-sinon");

// @todo Using real redis, because fakeredis cannot handle it
var redis = new Redis({
    port: 6379,
    host: "127.0.0.1"
});

function random(min, max){
    return Math.floor(Math.random() * (max - min)) + min;
}

function randomKey(){
    return "test:" + random(0,100) + ":" + new Date().getTime().toString().substr(-4) + ":" + random(0,100);
}

describe("Testing pool", function(){
    beforeEach(function(done){
        redis.flushdb(function(){
            done();
        })
    });

    it("Should throw exception while creating without redis connection", function(){
        (function(){new blpopPool()}).should.throw();
    });

    it("Should create pool with default options", function(){
        var pool = new blpopPool(redis);

        (pool._options).should.have.properties(["maxClients", "clientOptions"]);
        (pool._options.clientOptions).should.have.properties(["maxKeys", "timeout"]);
    });

    it("Should create new client when key is registered", function(){
        var pool = new blpopPool(redis);

        (pool._clients).should.be.empty();

        pool.registerKey("test", function(err, msg){});

        (pool._clients).should.not.be.empty();
    });

    it ("Should create new client when one client's keys spaces are out", function(){
        var pool = new blpopPool(redis, {
            maxClients: 0,
            clientOptions: {
                maxKeys: 2
            }
        });

        pool.registerKey(randomKey(), function(err, msg){});
        (pool._clients.length).should.equal(1);
        pool.registerKey(randomKey(), function(err, msg){});
        (pool._clients.length).should.equal(1);

        pool.registerKey(randomKey(), function(err, msg){});
        (pool._clients.length).should.equal(2);
    });

    it ("Should throw error when maximum clients reached", function(){
        var pool = new blpopPool(redis, {
            maxClients: 2,
            clientOptions: {
                maxKeys: 2
            }
        });

        for (var i=0;i<4;i++){
            pool.registerKey(randomKey(), function(err, msg){});
        }

        (function(){ pool.registerKey(randomKey(), function(err, msg){}) }).should.throw();
    });

    it ("Should remove key from client", function(){
        var pool = new blpopPool(redis);

        var key = randomKey();

        pool.registerKey(randomKey(), function(err, msg){});
        pool.registerKey(key, function(err, msg){});

        (pool._clients[0]._keys.length).should.equal(2);
        (pool._clients[0]._callbacks.length).should.equal(2);

        pool.removeKey(key);

        (pool._clients[0]._keys.length).should.equal(1);
        (pool._clients[0]._callbacks.length).should.equal(1);
    });

    it ("Should add key to client with empty spaces", function(){
        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 2
            }
        });

        var key = randomKey();

        // Create 3 clients each with 2 keys
        for (var i=0;i<5;i++){
            pool.registerKey(randomKey(), function(err, msg){});
            // Add key in the middle (...)
            if (i === 2){
                pool.registerKey(key, function(err, msg){});
            }
        }

        (pool._clients.length).should.equal(3);

        (pool._clients[0]._keys.length).should.equal(2);
        (pool._clients[1]._keys.length).should.equal(2);
        (pool._clients[2]._keys.length).should.equal(2);

        // remove one key from the client
        pool.removeKey(key);

        (pool._clients[1]._keys.length).should.equal(1);

        // Add key to the pool
        pool.registerKey(randomKey(), function(err, msg){});

        (pool._clients.length).should.equal(3);

        (pool._clients[0]._keys.length).should.equal(2);
        (pool._clients[1]._keys.length).should.equal(2);
        (pool._clients[2]._keys.length).should.equal(2);
    });

    // Todo Handle duplicate keys?
});

describe("Testing pool client", function(){
    beforeEach(function(done){
        redis.flushdb(function(){
            done();
        })
    });

    it("Should add key and callback if space available", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient();

        (client._keys.length).should.equal(0);
        (client._callbacks.length).should.equal(0);

        client.addKey("test", function(err, msg){});

        (client._keys.length).should.equal(1);
        (client._callbacks.length).should.equal(1);
    });

    it("Should not add key and callback if out of space", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient({maxKeys: 2});

        (client._keys.length).should.equal(0);
        (client._callbacks.length).should.equal(0);

        for (var i=0;i<3;i++){
            client.addKey(randomKey(), function(err, msg){});
        }

        (client._keys.length).should.equal(2);
        (client._callbacks.length).should.equal(2);
    });

    it ("Should remove key", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient();

        client.addKey("test", function(err, msg){});

        (client._keys.length).should.equal(1);
        (client._callbacks.length).should.equal(1);

        client.removeKey("test");

        (client._keys.length).should.equal(0);
        (client._callbacks.length).should.equal(0);
    });

    it ("Should rotate keys and callbacks - first to last", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient();

        var keys = [];
        var callbacks = [];

        for (var i=0;i<3;i++){
            callbacks.push(function(err, msg){return i;});
            keys.push(randomKey());

            client.addKey(keys[i], callbacks[i]);
        }

        (client._keys[0]).should.equal(keys[0]);
        (client._callbacks[0]).should.equal(callbacks[0]);

        client.rotateKeys();

        (client._keys[0]).should.equal(keys[1]);
        (client._callbacks[0]).should.equal(callbacks[1]);

        (client._keys[2]).should.equal(keys[0]);
        (client._callbacks[2]).should.equal(callbacks[0]);
    });

    it ("Should rotate keys and callbacks - any position to last", function(){
        var pool = new blpopPool(redis);
        var client = pool.createClient();

        var keys = [];
        var callbacks = [];

        for (var i=0;i<3;i++){
            callbacks.push(function(err, msg){return i});
            keys.push(randomKey());

            client.addKey(keys[i], callbacks[i]);
        }

        (client._keys[0]).should.equal(keys[0]);
        (client._callbacks[0]).should.equal(callbacks[0]);

        client.rotateKeys(1);

        (client._keys[0]).should.equal(keys[0]);
        (client._callbacks[0]).should.equal(callbacks[0]);

        (client._keys[1]).should.equal(keys[2]);
        (client._callbacks[1]).should.equal(callbacks[2]);

        (client._keys[2]).should.equal(keys[1]);
        (client._callbacks[2]).should.equal(callbacks[1]);
    });

    it ("Should call right callback on receiving message", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        for (var i=0;i<4;i++){
            pool.registerKey(randomKey(), function(err, msg){});
        }

        var callback = sinon.spy();
        var key = randomKey();

        pool.registerKey(key, callback);

        pool._clients[0].rotateKeys();
        pool._clients[0].rotateKeys();

        setTimeout(function(){
            redis.lpush(key, "a");

            setTimeout(function(){
                callback.should.be.calledOnce();
                done();
            }, 100);
        }, 2000);
    });

    it ("Should do key rotation on blpop callback", function(done){
        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var key = randomKey();

        pool.registerKey(key, function(err, msg){});

        setTimeout(function(){
            pool._clients[0].rotateKeys = sinon.spy();
            redis.lpush(key, "a");

            setTimeout(function () {
                pool._clients[0].rotateKeys.should.be.calledOnce();
                done();
            }, 500);
        },500);
    });

    it ("Should rotate key that received message at the end of the queue", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var key = randomKey();

        for (var i=0;i<5;i++){
            pool.registerKey(randomKey(), function(err, msg){});

            if (i === 2){
                pool.registerKey(key, function(err, msg){});
            }
        }

        setTimeout(function(){
            redis.lpush(key, "a");

            setTimeout(function(){
                should(pool._clients[0]._keys[pool._clients[0]._keys.length-1]).equal(key);
                done();
            }, 100);
        }, 2000);
    });

    it ("Should rotate keys correctly on timing out", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var key = randomKey();

        pool.registerKey(key, function(err, msg){});

        for (var i=0;i<5;i++){
            pool.registerKey(randomKey(), function(err, msg){});
        }

        setTimeout(function(){
            should(pool._clients[0]._keys[pool._clients[0]._keys.length-1]).equal(key);
            done();
        }, 2000);
    });

    it ("Should listen to all keys after timeout/new message", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var callback = sinon.spy();
        var key = randomKey();

        pool.registerKey(randomKey(), function(err, msg){});
        pool.registerKey(key, callback);

        callback.should.not.be.called();

        setTimeout(function(){
            redis.lpush(key, "a");

            setTimeout(function(){
                callback.should.be.calledOnce();
                done();
            }, 100);
        }, 2000);
    });

    it ("Should restart blpop after receiving message", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        pool.registerKey(randomKey(), function(err, msg){});

        pool._clients[0].startBlpop = sinon.spy();

        setTimeout(function(){
            redis.lpush(randomKey(), "a");

            setTimeout(function () {
                pool._clients[0].startBlpop.should.be.calledOnce();
                done();
            }, 100);
        },2000);
    });

    it ("Should restart blpop after timing out", function(done){
        this.timeout(3000);

        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        pool.registerKey(randomKey(), function(err, msg){});

        pool._clients[0].startBlpop = sinon.spy();

        setTimeout(function(){
            pool._clients[0].startBlpop.should.be.calledOnce();
            done();
        },2000);
    });

    it ("Should increment message count on receiving message", function(done){
        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        var key = randomKey();

        pool.registerKey(key, function(err, msg){});

        (pool._clients[0].messageCount).should.equal(0);

        setTimeout(function(){
            redis.lpush(key, "a");
            setTimeout(function(){
                (pool._clients[0].messageCount).should.equal(1);
                done();
            }, 100);
        },100);
    });

    it ("Should not increment message count on timing out", function(done){
        var pool = new blpopPool(redis, {
            clientOptions: {
                maxKeys: 10,
                timeout: 1
            }
        });

        pool.registerKey(randomKey(), function(err, msg){});

        (pool._clients[0].messageCount).should.equal(0);

        setTimeout(function(){
            (pool._clients[0].messageCount).should.equal(0);
            done();
        },1500);
    });

    // @todo finish testcase
    it ("Should log warning when receiving message for unknown key", function(){
        // true.should.be.false();
    });

    // @todo finish testcase
    it ("Should throw error if received redis error and have no callback", function(){
        // true.should.be.false();
    });

    it ("Should not start blpop if there are no keys in the queue", function(done){
        var pool = new blpopPool(redis);

        var client = pool.createClient({timeout: 1});

        client.onMessage = sinon.spy();

        client.startBlpop();

        setTimeout(function(){
            client.onMessage.should.not.be.called();
            done();
        }, 1500);
    });
});
<|endoftext|>


<commit_before>$(document).ready(function () {

	function exportTableToCSV($table, filename) {

		var $rows = $table.find('tr:visible'),

			tmpColDelim = String.fromCharCode(11),
			tmpRowDelim = String.fromCharCode(0),

			colDelim = '","',
			rowDelim = '"\r\n"',

			csv = '"' + $rows.map(function (i, row) {
				var $row = $(row),
					$cols = $row.find('th, td');

				return $cols.map(function (j, col) {
					var $col = $(col),
						text = $col.text();

					return text.replace(/"/g, '""');

				}).get().join(tmpColDelim);

			}).get().join(tmpRowDelim)
				.split(tmpRowDelim).join(rowDelim)
				.split(tmpColDelim).join(colDelim) + '"',

			csvData = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csv);

		$(this)
			.attr({
			'download': filename,
				'href': csvData,
				'target': '_blank'
		});
	}

	function exportAddressesToCSV($table, filename) {

		var fullnameIndex = $table.find('tr th[data-content=fullname]').index();
		var adrIndex = $table.find('tr th[data-content=adr]').index();

		var $rows = $table.find('tr:visible'),

			tmpColDelim = String.fromCharCode(11),
			tmpRowDelim = String.fromCharCode(0),

			colDelim = '","',
			rowDelim = '"\r\n"';

		var csv = '"' + $rows.map(function (i, row) {
				if (i == 0)
				{
					return null;
				}

				var $row = $(row),
					fullname = $row.find('td:eq(' + fullnameIndex + ') a').text(),
					adr = $row.find('td:eq(' + adrIndex + ')').text().split(',');
				adr.unshift(fullname);

				return adr.map(function (str, i) {
					return str.trim().replace(/"/g, '""');

				}).join(tmpColDelim);

			}).get().join(tmpRowDelim)
				.split(tmpRowDelim).join(rowDelim)
				.split(tmpColDelim).join(colDelim) + '"',

			csvData = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csv);

		$(this)
			.attr({
			'download': filename,
				'href': csvData,
				'target': '_blank'
		});
	}

	$('a.csv').click(function (event) {
		exportTableToCSV.apply(this, [$('table.csv'), 'export.csv']);
	});

	$('a.csv-adr').click(function (event) {
		exportAddressesToCSV.apply(this, [$('table.csv-adr'), 'export_adr.csv']);
	});
});
<commit_msg>trim whitespace in csv<commit_after>$(document).ready(function () {

	function exportTableToCSV($table, filename) {

		var $rows = $table.find('tr:visible'),

			tmpColDelim = String.fromCharCode(11),
			tmpRowDelim = String.fromCharCode(0),

			colDelim = '","',
			rowDelim = '"\r\n"',

			csv = '"' + $rows.map(function (i, row) {
				var $row = $(row),
					$cols = $row.find('th, td');

				return $cols.map(function (j, col) {
					var $col = $(col),
						text = $col.text();

					return text.replace(/"/g, '""').trim();

				}).get().join(tmpColDelim);

			}).get().join(tmpRowDelim)
				.split(tmpRowDelim).join(rowDelim)
				.split(tmpColDelim).join(colDelim) + '"',

			csvData = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csv);

		$(this)
			.attr({
			'download': filename,
				'href': csvData,
				'target': '_blank'
		});
	}

	function exportAddressesToCSV($table, filename) {

		var fullnameIndex = $table.find('tr th[data-content=fullname]').index();
		var adrIndex = $table.find('tr th[data-content=adr]').index();

		var $rows = $table.find('tr:visible'),

			tmpColDelim = String.fromCharCode(11),
			tmpRowDelim = String.fromCharCode(0),

			colDelim = '","',
			rowDelim = '"\r\n"';

		var csv = '"' + $rows.map(function (i, row) {
				if (i == 0)
				{
					return null;
				}

				var $row = $(row),
					fullname = $row.find('td:eq(' + fullnameIndex + ') a').text(),
					adr = $row.find('td:eq(' + adrIndex + ')').text().split(',');
				adr.unshift(fullname);

				return adr.map(function (str, i) {
					return str.trim().replace(/"/g, '""');

				}).join(tmpColDelim);

			}).get().join(tmpRowDelim)
				.split(tmpRowDelim).join(rowDelim)
				.split(tmpColDelim).join(colDelim) + '"',

			csvData = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csv);

		$(this)
			.attr({
			'download': filename,
				'href': csvData,
				'target': '_blank'
		});
	}

	$('a.csv').click(function (event) {
		exportTableToCSV.apply(this, [$('table.csv'), 'export.csv']);
	});

	$('a.csv-adr').click(function (event) {
		exportAddressesToCSV.apply(this, [$('table.csv-adr'), 'export_adr.csv']);
	});
});
<|endoftext|>


<commit_before>var utils = module.exports = exports = {
  SHA1: require('./sha1')
};

// Extend existing objects without creating references
//
// Return: `Object`
utils.extend = function (original, context) {
  var output = JSON.parse(JSON.stringify(original || {})), key;
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        output[key] = utils.extend(output[key] || {}, context[key]);
      else
        output[key] = context[key];
  return output;
};

// Extend objects and convert them to a serialized query string
//
// Return: `Object`
utils.serialExtend = function (original, context, prefix) {
  var output = JSON.parse(JSON.stringify(original || {})), i, key, value;
  for (i in context) {
    if (!context.hasOwnProperty(i)) continue;
    else key = prefix ? prefix + "[" + i + "]" : i, value = context[i];
    if (Object.prototype.toString.call(value) === '[object Object]')
      output = utils.serialExtend(output, value, key);
    else
      output[key] = value;
  }
  return output;
};

// Checks whether host closes their connection early
//
// Return: `Boolean`
utils.isAnEarlyCloseHost = function (hostname) {
  return hostname && hostname.match(".*google(apis)?.com$");
};

// Determines whether response contains Binary content
//
// Return: `Boolean`
utils.isBinaryContent = function (response) {
  return (!response.headers || !response.headers["content-type"]) ? false : (response.headers["content-type"].match(/^(image|audio|video)\//));
};

// Removes leading and trailing whitespace
//
// Return: `String`
utils.trim = function (string) {
  return string.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
};

// Encodes and replaces values that encodeURIComponent doesn't.
// The only ones you can ignore with OAuth are: - _ . ~
// see - http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent
//
// Return: `String`
utils.encodeData = function (data) {
  if (data === "" || !data) return "";
  return encodeURIComponent(data).
    replace(/\!/g, "%21").
    replace(/\'/g, "%27").
    replace(/\(/g, "%28").
    replace(/\)/g, "%29").
    replace(/\*/g, "%2A");
};

// Decode URI information with regards to encoding process
//
// Return: `String`
utils.decodeData = function (data) {
  if (data !== null) data = data.replace(/\+/g, ' ');
  return decodeURIComponent(data);
};

// Scans header string for key-value information and bearer details
//
// Return: `Object` unless invalid headers then `Boolean` (false).
utils.parseHeader = function (header) {
  if (header.indexOf(',') === -1) return false;
  var params = {}, match;
  header = utils.trim(header);

  header.split(",").forEach(function (v, i) {
    match = v.match(/(\w+)(?:([:=]) ?"?([\w\+\%\=\;]+)?"?)?/);

    if (match[2] === "=")
      params[match[1]] = utils.decodeData(match[3] || "");
    else {
      params['bearer'] = utils.decodeData(match[1]);

      if (match.input.indexOf(" ")) {
        match = match.input.split(" ")[1].match(/(\w+)(?:([:=]) ?"?([\w\+\%\=\;]+)?"?)?/);
        if (match[2] === "=") params[match[1]] = utils.decodeData(match[3] || "");
      }
    }
  });

  return params;
};<commit_msg>Version has periods.<commit_after>var utils = module.exports = exports = {
  SHA1: require('./sha1')
};

// Extend existing objects without creating references
//
// Return: `Object`
utils.extend = function (original, context) {
  var output = JSON.parse(JSON.stringify(original || {})), key;
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        output[key] = utils.extend(output[key] || {}, context[key]);
      else
        output[key] = context[key];
  return output;
};

// Extend objects and convert them to a serialized query string
//
// Return: `Object`
utils.serialExtend = function (original, context, prefix) {
  var output = JSON.parse(JSON.stringify(original || {})), i, key, value;
  for (i in context) {
    if (!context.hasOwnProperty(i)) continue;
    else key = prefix ? prefix + "[" + i + "]" : i, value = context[i];
    if (Object.prototype.toString.call(value) === '[object Object]')
      output = utils.serialExtend(output, value, key);
    else
      output[key] = value;
  }
  return output;
};

// Checks whether host closes their connection early
//
// Return: `Boolean`
utils.isAnEarlyCloseHost = function (hostname) {
  return hostname && hostname.match(".*google(apis)?.com$");
};

// Determines whether response contains Binary content
//
// Return: `Boolean`
utils.isBinaryContent = function (response) {
  return (!response.headers || !response.headers["content-type"]) ? false : (response.headers["content-type"].match(/^(image|audio|video)\//));
};

// Removes leading and trailing whitespace
//
// Return: `String`
utils.trim = function (string) {
  return string.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
};

// Encodes and replaces values that encodeURIComponent doesn't.
// The only ones you can ignore with OAuth are: - _ . ~
// see - http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent
//
// Return: `String`
utils.encodeData = function (data) {
  if (data === "" || !data) return "";
  return encodeURIComponent(data).
    replace(/\!/g, "%21").
    replace(/\'/g, "%27").
    replace(/\(/g, "%28").
    replace(/\)/g, "%29").
    replace(/\*/g, "%2A");
};

// Decode URI information with regards to encoding process
//
// Return: `String`
utils.decodeData = function (data) {
  if (data !== null) data = data.replace(/\+/g, ' ');
  return decodeURIComponent(data);
};

// Scans header string for key-value information and bearer details
//
// Return: `Object` unless invalid headers then `Boolean` (false).
utils.parseHeader = function (header) {
  if (header.indexOf(',') === -1) return false;
  var params = {}, match;
  header = utils.trim(header);

  header.split(",").forEach(function (v, i) {
    match = v.match(/(\w+)(?:([:=]) ?"?([\w\+\%\=\;]+)?"?)?/);

    if (match[2] === "=")
      params[match[1]] = utils.decodeData(match[3] || "");
    else {
      params['bearer'] = utils.decodeData(match[1]);

      if (match.input.indexOf(" ")) {
        match = match.input.split(" ")[1].match(/(\w+)(?:([:=]) ?"?([\w\+\%\=\;\.]+)?"?)?/);
        if (match[2] === "=") params[match[1]] = utils.decodeData(match[3] || "");
      }
    }
  });

  return params;
};<|endoftext|>


<commit_before>var assert = require('assert');
var autoPush = require('../index.js');
var fs = require('fs');
var http2 = require('http2');
require('should');

var tlsOptions = {
  key: fs.readFileSync(__dirname + '/ssl/key.pem'),
  cert: fs.readFileSync(__dirname + '/ssl/cert.pem')
};

var port = 8100;

function createServer(routes, options, responseStrategy) {
  return http2.createServer(tlsOptions, autoPush(function(req, res) {
    var data = routes[req.url];
    var status = data.status || 200;
    var contentType = data.contentType || 'text/html';
    var content = data.content;

    res.writeHead(status, {
      'content-type': contentType
    });
    if (!responseStrategy) {
      res.end(content);
    } else if (responseStrategy === 1) {
      res.write(content);
      res.end();
    }

  }, options));
}

function testSingleResource(routes, options, accessURL, responseStrategy, wontPush, done) {
  var server = createServer(routes, options, responseStrategy);
  server.listen(++port);

  var subresourceCount = Object.keys(routes).length - 1;

  var request = http2.get('https://localhost:' + port + accessURL);

  var pushedRequestCount = 0;
  var pushedResponseCount = 0;

  var log = [];
  var push = function(message) {
    // console.log(message);
    log.push(message);
  }

  request.on('response', function(response) {
    push('response');
    response.statusCode.should.equal(200);
    response.on('data', function(data) {
      push('response-data');
      pushedRequestCount.should.equal(subresourceCount);
      data.toString().should.equal(routes[accessURL].content);
    });
    response.on('end', function() {
      push('response-end');
      if (wontPush) {
        done();
      }
    });

  });

  request.on('push', function(pushRequest) {
    push('push:' + pushRequest.url);
    if (wontPush) {
      assert.fail('unexpectedly pushed');
    }
    pushedRequestCount++;
    pushRequest.on('response', function(pushResponse) {
      push('push-response:' + pushRequest.url);
      pushResponse.statusCode.should.equal(200);
      pushResponse.on('data', function(data) {
        push('push-response-data:' + pushRequest.url);
        pushedResponseCount++;
        data.toString().should.equal(routes[pushRequest.url].content);
        // console.log(pushedResponseCount +'/' + subresourceCount);
        if (pushedResponseCount === subresourceCount) {
          pushedRequestCount.should.equal(pushedResponseCount);
          // console.log(log);
          server.close(function() {

          });
          done();
        }
      });
    });
  });
}

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

describe('auto-push', function() {

  it('should push .js', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/', 0, false, done);
  });

  it('should push .css', function(done) {
    testSingleResource({
      '/': {
        content: '<link rel="stylesheet" href="/app.css"></link>'
      },
      '/app.css': {
        content: 'body { color: red; }'
      }
    }, null, '/', 0, false, done);
  });

  it('should push image', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/image.png': {
        content: '123'
      }
    }, null, '/', 0, false, done);
  });

  it('should push image2', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/image.png': {
        content: '123'
      }
    }, null, '/', 0, false, done);
  });

  it('should push .js --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/', 1, false, done);
  });

  it('should push .css --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: '<link rel="stylesheet" href="/app.css"></link>'
      },
      '/app.css': {
        content: 'body { color: red; }'
      }
    }, null, '/', 1, false, done);
  });

  it('should push image --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/image.png': {
        content: '123'
      }
    }, null, '/', 1, false, done);
  });

  it('should push image2 --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/image.png': {
        content: '123'
      }
    }, null, '/', 1, false, done);
  });

  it('should resolve url 1', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 2', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 3', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 4', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 5', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 1a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  it('should resolve url 2a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  it('should resolve url 3a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  it('should resolve url 4a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  it('should resolve url 5a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  // it('should NOT push if tag is illegular 1', function(done) {
  //   testSingleResource({
  //      '/': { content: ''},
  //     '/app.js': { content: 'console.log("hello")'}
  //   }, null, '/', 0, true, done);
  // });

  it('should push pre-related resources', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, {
      relations: {
        '/': ['/app.js']
      }
    }, '/', 0, false, done);
  });

  it('should push pre-related resources 2', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, {
      relations: {
        '/': ['./app.js']
      }
    }, '/', 0, false, done);
  });

  it('should push pre-related resources 3', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, {
      relations: {
        '/foo/': ['../app.js']
      }
    }, '/foo/', 0, false, done);
  });

  it('should recursively push', function(done) {
    testSingleResource({
      '/': {
        content: '<link rel="stylesheet" href="app.css"></link>'
      },
      '/app.css': {
        contentType: 'text/css',
        content: 'body { background: url("a.jpeg"); }'
      },
      '/a.jpeg': {
        content: '_'
      }
    }, null, '/', 0, false, done);
  });

  it('should recursively push --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: '<link rel="stylesheet" href="app.css"></link>'
      },
      '/app.css': {
        contentType: 'text/css',
        content: 'body { background: url("a.jpeg"); }'
      },
      '/a.jpeg': {
        content: '_'
      }
    }, null, '/', 0, false, done);
  });

});
<commit_msg>raise coverage<commit_after>var assert = require('assert');
var autoPush = require('../index.js');
var fs = require('fs');
var http2 = require('http2');
require('should');

var tlsOptions = {
  key: fs.readFileSync(__dirname + '/ssl/key.pem'),
  cert: fs.readFileSync(__dirname + '/ssl/cert.pem')
};

var port = 8100;

function createServer(routes, options, responseStrategy) {
  return http2.createServer(tlsOptions, autoPush(function(req, res) {
    var data = routes[req.url];
    var status = data.status || 200;
    var contentType = data.contentType || 'text/html';
    var content = data.content;

    if (!responseStrategy) {
      res.writeHead(status, {
        'content-type': contentType
      });
      res.end(content);
    } else if (responseStrategy === 1) {
      res.statusCode = status;
      res.setHeader('content-type', contentType);
      res.write(content);
      res.end();
    }

  }, options));
}

function testSingleResource(routes, options, accessURL, responseStrategy, wontPush, done) {
  var server = createServer(routes, options, responseStrategy);
  server.listen(++port);

  var subresourceCount = Object.keys(routes).length - 1;

  var request = http2.get('https://localhost:' + port + accessURL);

  var pushedRequestCount = 0;
  var pushedResponseCount = 0;

  var log = [];
  var push = function(message) {
    // console.log(message);
    log.push(message);
  }

  request.on('response', function(response) {
    push('response');
    response.statusCode.should.equal(200);
    response.on('data', function(data) {
      push('response-data');
      pushedRequestCount.should.equal(subresourceCount);
      data.toString().should.equal(routes[accessURL].content);
    });
    response.on('end', function() {
      push('response-end');
      if (wontPush) {
        done();
      }
    });

  });

  request.on('push', function(pushRequest) {
    push('push:' + pushRequest.url);
    if (wontPush) {
      assert.fail('unexpectedly pushed');
    }
    pushedRequestCount++;
    pushRequest.on('response', function(pushResponse) {
      push('push-response:' + pushRequest.url);
      pushResponse.statusCode.should.equal(200);
      pushResponse.on('data', function(data) {
        push('push-response-data:' + pushRequest.url);
        pushedResponseCount++;
        data.toString().should.equal(routes[pushRequest.url].content);
        // console.log(pushedResponseCount +'/' + subresourceCount);
        if (pushedResponseCount === subresourceCount) {
          pushedRequestCount.should.equal(pushedResponseCount);
          // console.log(log);
          server.close(function() {

          });
          done();
        }
      });
    });
  });
}

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

describe('auto-push', function() {

  it('should push .js', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/', 0, false, done);
  });

  it('should push .css', function(done) {
    testSingleResource({
      '/': {
        content: '<link rel="stylesheet" href="/app.css"></link>'
      },
      '/app.css': {
        content: 'body { color: red; }',
        contentType: 'text/css'
      }
    }, null, '/', 0, false, done);
  });

  it('should push image', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/image.png': {
        content: '123'
      }
    }, null, '/', 0, false, done);
  });

  it('should push image2', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/image.png': {
        content: '123'
      }
    }, null, '/', 0, false, done);
  });

  it('should push .js --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/', 1, false, done);
  });

  it('should push .css --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: '<link rel="stylesheet" href="/app.css"></link>'
      },
      '/app.css': {
        content: 'body { color: red; }',
        contentType: 'text/css'
      }
    }, null, '/', 1, false, done);
  });

  it('should push image --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/image.png': {
        content: '123'
      }
    }, null, '/', 1, false, done);
  });

  it('should push image2 --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/image.png': {
        content: '123'
      }
    }, null, '/', 1, false, done);
  });

  it('should resolve url 1', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 2', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 3', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 4', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 5', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/', 0, false, done);
  });

  it('should resolve url 1a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  it('should resolve url 2a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  it('should resolve url 3a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  it('should resolve url 4a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  it('should resolve url 5a', function(done) {
    testSingleResource({
      '/foo/index.html': {
        content: ''
      },
      '/foo/app.js': {
        content: 'console.log("hello")'
      }
    }, null, '/foo/index.html', 0, false, done);
  });

  // it('should NOT push if tag is illegular 1', function(done) {
  //   testSingleResource({
  //      '/': { content: ''},
  //     '/app.js': { content: 'console.log("hello")'}
  //   }, null, '/', 0, true, done);
  // });

  it('should push pre-related resources', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, {
      relations: {
        '/': ['/app.js']
      }
    }, '/', 0, false, done);
  });

  it('should push pre-related resources 2', function(done) {
    testSingleResource({
      '/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, {
      relations: {
        '/': ['./app.js']
      }
    }, '/', 0, false, done);
  });

  it('should push pre-related resources 3', function(done) {
    testSingleResource({
      '/foo/': {
        content: ''
      },
      '/app.js': {
        content: 'console.log("hello")'
      }
    }, {
      relations: {
        '/foo/': ['../app.js']
      }
    }, '/foo/', 0, false, done);
  });

  it('should recursively push', function(done) {
    testSingleResource({
      '/': {
        content: '<link rel="stylesheet" href="app.css"></link>'
      },
      '/app.css': {
        contentType: 'text/css',
        content: 'body { background: url("a.jpeg"); }'
      },
      '/a.jpeg': {
        content: '_'
      }
    }, null, '/', 0, false, done);
  });

  it('should recursively push --strategy1', function(done) {
    testSingleResource({
      '/': {
        content: '<link rel="stylesheet" href="app.css"></link>'
      },
      '/app.css': {
        contentType: 'text/css',
        content: 'body { background: url("a.jpeg"); }'
      },
      '/a.jpeg': {
        content: '_'
      }
    }, null, '/', 0, false, done);
  });

});
<|endoftext|>


<commit_before>function update_ranking()
{
	$.ajax({
		type: 'GET',
		url: 'ajax.php?m=get_ranking',
		processData: false,
		contentType: false,
		success: function(xml) {
			var table = $( '<table>' );

			$( xml ).find( 'team' ).each
			(
				function()
				{
					var trow = $( '<tr>' );
					$( '<td>' ).text( $( this ).find( 'rank' ).text() ).appendTo( trow );
					$( '<td>' ).text( $( this ).find( 'name' ).text() ).appendTo( trow );
					$( '<td>' ).addClass( 'score' ).text( $( this ).find( 'score' ).text() ).appendTo( trow );

					trow.appendTo( table );
				}
			);

			$( '#ranking' ).html( table.html() );
		},
		error: function(data)	{
			console.log(data);
		}
	});
	return false;
}<commit_msg>Added table header<commit_after>function update_ranking()
{
	$.ajax({
		type: 'GET',
		url: 'ajax.php?m=get_ranking',
		processData: false,
		contentType: false,
		success: function(xml) {
			var table = $( '<table>' );

			var thead = $( '<thead><tr>' );
			$( '<td>' ).text( 'Rank' ).appendTo( thead );
			$( '<td>' ).text( 'Team Name' ).appendTo( thead );
			$( '<td>' ).text( 'Score' ).appendTo( thead );

			$( xml ).find( 'team' ).each
			(
				function()
				{
					var trow = $( '<tr>' );
					$( '<td>' ).text( $( this ).find( 'rank' ).text() ).appendTo( trow );
					$( '<td>' ).text( $( this ).find( 'name' ).text() ).appendTo( trow );
					$( '<td>' ).addClass( 'score' ).text( $( this ).find( 'score' ).text() ).appendTo( trow );

					trow.appendTo( table );
				}
			);

			$( '#ranking' ).html( table.html() );
		},
		error: function(data)	{
			console.log(data);
		}
	});
	return false;
}<|endoftext|>


<commit_before>import BaseScene from '../BaseScene/BaseScene';
import Player from '../../Three/Objects/Player/Player';
import Bullet from '../../Three/Objects/Bullet/Bullet';
import PlayerService from '../../Manager/PlayerManager/PlayerManager';
import playersService from '../../Manager/PlayersManager/PlayersManager';
import BulletService from '../../Manager/BulletManager/BulletManager';
import bulletsService from '../../Manager/BulletsManager/BulletsManager';
import playerStats from '../../Tools/PlayerStats/PlayerStats';
import map from '../../Tools/Map/Map';
import Helper from '../../Tools/Helper/Helper';
import CollisionService from '../../Manager/CollisionManager/CollisionManager';
import AIService from '../../Manager/AIManager/AIManager';
import musicService from '../../Tools/MusicService/MusicService';
import GameWebSocketManager from '../../Manager/GameWebSocketManager/GameWebSocketManager';
import {
  UNITSIZE,
  MOVESPEEDAI,
  BULLETMOVESPEED
} from '../../Constants/Constants';
import {
  INITIALIZE_PLAYER,
  SNAPSHOT,
  REMOVE_PLAYER
} from '../../Constants/MultiPlayer';

export default class MultiPlayerScene extends BaseScene {
  constructor(keys, mouse, functionGo) {
    super(keys, mouse, functionGo);

    this._game = false;
    this._webSocketManager = new GameWebSocketManager();
  }

  set game(value) {
    this._game = value;
  }

  get game() {
    return this._game;
  }

  _init() {
    this._webSocketManager.setOnMessage(this._setUpWebSockets());
    musicService.stopBackground();

    this._initScenePreferences();

    this._makeScene();

    this._setUpRender();
  }

  _setUpWebSockets() {
    return (content, data) => {
      switch (content.type) {
        case INITIALIZE_PLAYER:
          console.log(data);
          this._player.id = data;
          break;
        case SNAPSHOT:
          // update leaderboard

          if (data.shot) {
            // anim
          }

          // change hp

          if (data.hp === 0) {
            // reborn
          }

          // show death on screen

          data.players.forEach(player => {
            const playerId = player.id;

            if (playerId === this._player.id) {
              return;
            }

            const playerPosition = player.position;

            if (playerPosition === null) {
              console.log('Враг без координат');
              return;
            }

            this._players = {};

            // players - manager
            if (this._players.getFullPlayer(`id${playerId}`) === undefined) {
              const playerObject = new Player().object;
              this._players.setFullPlayer(playerId, playerObject);
              this._players.getFullPlayer(`id${playerId}`)
                .position.copy(playerPosition);

              this._players.add(new PlayerService(playerObject, 100));

              this._scene.add(playerObject);

              // generate table
            } else {
              this._players.getFullPlayer(`id${playerId}`)
                .position.copy(playerPosition);
            }
          });
          break;
        case REMOVE_PLAYER:
          data.forEach(element => {
            this._scene.remove(this._players.getFullPlayer(element));
            this._players.removeFullPlayer(element);
          });
          break;
        default:
          break;
      }
    };
  }

  _animate() {
    if (this._isAnimate) {
      requestAnimationFrame(this._animate.bind(this));
    }

    this._render();

    let {x, y, z} = this._camera.position;
    const position = {x, y, z};

    x = this._camera.rotation.x;
    y = this._camera.rotation.y;
    z = this._camera.rotation.z;

    const camera = {x, y, z};

    let json = {
      type: 'application.mechanics.base.UserSnap',
      data: {
        position,
        id: this._player.id,
        camera,
        firing: false
      }
    };

    this._webSocketManager.send(json);
  }

  _addAI() {
    const position = Helper.getMapSector(this._camera.position);

    let [x, z] = Helper.getRandomPosition();
    while (map._map[x][z] > 0 || (x === position.x && z === position.z)) {
      [x, z] = Helper.getRandomPosition();
    }

    x = Math.floor(x - map.width / 2) * UNITSIZE;
    z = Math.floor(z - map.width / 2) * UNITSIZE;

    const playerObject = new Player().object;
    playerObject.position.set(x, UNITSIZE * 0.15, z);

    playersService.add(new PlayerService(playerObject, 100));
    this._scene.add(playerObject);
  }

  _updateBullets(delta) {
    for (let i in bulletsService.all) {
      const bullet = bulletsService.getBullet(i);
      const position = bullet.object.position;

      if (CollisionService.collisionBulletWithWall(position)) {
        bulletsService.remove(i);
        this._scene.remove(bullet.object);

        continue;
      }

      // Collide with AI
      let hit = CollisionService.collisionBulletWithAi(
        this._scene,
        playersService,
        bulletsService,
        bullet,
        position,
        i
      );

      // Bullet hits player
      CollisionService.collisionBulletWithPlayer(
        this._scene,
        playerStats,
        bulletsService,
        position,
        this._camera,
        bullet,
        i
      );

      if (!hit) {
        const speed = delta * BULLETMOVESPEED;
        const direction = bullet.object.ray.direction;

        bullet.object.translateX(speed * direction.x);
        bullet.object.translateZ(speed * direction.z);
      }
    }
  }

  _render() {
    const delta = this._clock.getDelta();
    this._keys.update(this._camera, delta, Helper.checkWallCollision.bind(this));

    // Update bullets.
    this._updateBullets(delta);

    if (this._game) {
      for (let i in playersService.all) {
        AIService.updateAI(
          this._scene,
          playersService,
          playerStats,
          delta * MOVESPEEDAI,
          i,
          this._addAI.bind(this)
        );

        const player = playersService.getPlayer(i);
        const sector = Helper.getMapSector(player.object.position);

        AIService.shoot(
          this._camera,
          player,
          sector,
          this._createBullet.bind(this)
        );
      }
    }

    this._renderer.render(this._scene, this._camera);

    // Death
    this._death();
  }

  _death() {
    if (playerStats.health <= 0) {
      this.stop();
      this._keys._deactivateTable();

      musicService.startEndGame();
      this._openEndGame();

      setTimeout(() => {
        localStorage.setItem('singlePlayerScore', playerStats.kills * 100);
        this._closeEndGame();
        this._goToFromGame();
        location.reload();
      }, 4000);
    }
  }

  _createBullet(object) {
    if (object === undefined) {
      object = this._camera;
    }

    const bullet = new BulletService(new Bullet().object, object, this._camera);

    bulletsService.add(bullet);
    this._scene.add(bullet.object);
  }
}
<commit_msg>update mp<commit_after>import BaseScene from '../BaseScene/BaseScene';
import Player from '../../Three/Objects/Player/Player';
import Bullet from '../../Three/Objects/Bullet/Bullet';
import PlayerService from '../../Manager/PlayerManager/PlayerManager';
import playersService from '../../Manager/PlayersManager/PlayersManager';
import BulletService from '../../Manager/BulletManager/BulletManager';
import bulletsService from '../../Manager/BulletsManager/BulletsManager';
import playerStats from '../../Tools/PlayerStats/PlayerStats';
import map from '../../Tools/Map/Map';
import Helper from '../../Tools/Helper/Helper';
import CollisionService from '../../Manager/CollisionManager/CollisionManager';
import AIService from '../../Manager/AIManager/AIManager';
import musicService from '../../Tools/MusicService/MusicService';
import GameWebSocketManager from '../../Manager/GameWebSocketManager/GameWebSocketManager';
import {
  UNITSIZE,
  MOVESPEEDAI,
  BULLETMOVESPEED
} from '../../Constants/Constants';
import {
  INITIALIZE_PLAYER,
  SNAPSHOT,
  REMOVE_PLAYER
} from '../../Constants/MultiPlayer';

let a = false;

export default class MultiPlayerScene extends BaseScene {
  constructor(keys, mouse, functionGo) {
    super(keys, mouse, functionGo);

    this._game = false;
    this._webSocketManager = new GameWebSocketManager();
  }

  set game(value) {
    this._game = value;
  }

  get game() {
    return this._game;
  }

  _init() {
    this._webSocketManager.setOnMessage(this._setUpWebSockets());
    musicService.stopBackground();

    this._initScenePreferences();

    this._makeScene();

    this._setUpRender();
  }

  _setUpWebSockets() {
    return (content, data) => {
      switch (content.type) {
        case INITIALIZE_PLAYER:
          console.log(data);
          this._player.id = data;
          break;
        case SNAPSHOT:
          // update leaderboard

          if (data.shot) {
            // anim
          }

          // change hp

          if (data.hp === 0) {
            // reborn
          }

          // show death on screen

          data.players.forEach(player => {
            const playerId = player.id;

            if (playerId === this._player.id) {
              return;
            }

            const playerPosition = player.position;

            if (playerPosition === null) {
              console.log('Враг без координат');
              return;
            }

            this._players = {};

            // players - manager
            if (this._players.getFullPlayer(`id${playerId}`) === undefined) {
              const playerObject = new Player().object;
              this._players.setFullPlayer(playerId, playerObject);
              this._players.getFullPlayer(`id${playerId}`)
                .position.copy(playerPosition);

              this._players.add(new PlayerService(playerObject, 100));

              this._scene.add(playerObject);

              // generate table
            } else {
              this._players.getFullPlayer(`id${playerId}`)
                .position.copy(playerPosition);
            }
          });
          break;
        case REMOVE_PLAYER:
          data.forEach(element => {
            this._scene.remove(this._players.getFullPlayer(element));
            this._players.removeFullPlayer(element);
          });
          break;
        default:
          break;
      }
    };
  }

  _animate() {
    if (this._isAnimate) {
      requestAnimationFrame(this._animate.bind(this));
    }

    this._render();

    let {x, y, z} = this._camera.position;
    const position = {x, y, z};

    x = this._camera.rotation.x;
    y = this._camera.rotation.y;
    z = this._camera.rotation.z;

    const camera = {x, y, z};

    let json = {
      type: 'application.mechanics.base.UserSnap',
      data: {
        position,
        id: this._player.id,
        camera,
        firing: false
      }
    };

    if (a) {
      this._webSocketManager.send(json);
    } else {
      setTimeout(() => {
        a = true;
        this._webSocketManager.send(json);
      }, 4000);
    }
  }

  _addAI() {
    const position = Helper.getMapSector(this._camera.position);

    let [x, z] = Helper.getRandomPosition();
    while (map._map[x][z] > 0 || (x === position.x && z === position.z)) {
      [x, z] = Helper.getRandomPosition();
    }

    x = Math.floor(x - map.width / 2) * UNITSIZE;
    z = Math.floor(z - map.width / 2) * UNITSIZE;

    const playerObject = new Player().object;
    playerObject.position.set(x, UNITSIZE * 0.15, z);

    playersService.add(new PlayerService(playerObject, 100));
    this._scene.add(playerObject);
  }

  _updateBullets(delta) {
    for (let i in bulletsService.all) {
      const bullet = bulletsService.getBullet(i);
      const position = bullet.object.position;

      if (CollisionService.collisionBulletWithWall(position)) {
        bulletsService.remove(i);
        this._scene.remove(bullet.object);

        continue;
      }

      // Collide with AI
      let hit = CollisionService.collisionBulletWithAi(
        this._scene,
        playersService,
        bulletsService,
        bullet,
        position,
        i
      );

      // Bullet hits player
      CollisionService.collisionBulletWithPlayer(
        this._scene,
        playerStats,
        bulletsService,
        position,
        this._camera,
        bullet,
        i
      );

      if (!hit) {
        const speed = delta * BULLETMOVESPEED;
        const direction = bullet.object.ray.direction;

        bullet.object.translateX(speed * direction.x);
        bullet.object.translateZ(speed * direction.z);
      }
    }
  }

  _render() {
    const delta = this._clock.getDelta();
    this._keys.update(this._camera, delta, Helper.checkWallCollision.bind(this));

    // Update bullets.
    this._updateBullets(delta);

    if (this._game) {
      for (let i in playersService.all) {
        AIService.updateAI(
          this._scene,
          playersService,
          playerStats,
          delta * MOVESPEEDAI,
          i,
          this._addAI.bind(this)
        );

        const player = playersService.getPlayer(i);
        const sector = Helper.getMapSector(player.object.position);

        AIService.shoot(
          this._camera,
          player,
          sector,
          this._createBullet.bind(this)
        );
      }
    }

    this._renderer.render(this._scene, this._camera);

    // Death
    this._death();
  }

  _death() {
    if (playerStats.health <= 0) {
      this.stop();
      this._keys._deactivateTable();

      musicService.startEndGame();
      this._openEndGame();

      setTimeout(() => {
        localStorage.setItem('singlePlayerScore', playerStats.kills * 100);
        this._closeEndGame();
        this._goToFromGame();
        location.reload();
      }, 4000);
    }
  }

  _createBullet(object) {
    if (object === undefined) {
      object = this._camera;
    }

    const bullet = new BulletService(new Bullet().object, object, this._camera);

    bulletsService.add(bullet);
    this._scene.add(bullet.object);
  }
}
<|endoftext|>


<commit_before><commit_msg>added safety check to prevent duplicate items in list<commit_after><|endoftext|>


<commit_before>
var utils = {};

// uppercase first letter
utils.upperCaseFirstLetter = function(str) {
  return str.replace(str.charAt(0), function(a) {
    return a.toUpperCase();
  });
};

// get image format
utils.getImageFormat = function(str) {
  var format = str.substr(str.lastIndexOf('.') + 1, str.length);
  format = format === 'jpg' ? 'jpeg' : format;
  return 'image/' + format;
};

// whether is browser
utils.isBrowser = function() {
  var isElectron = utils.isElectron();
  var isNW = utils.isNW();
  return !isElectron && !isNW && !(typeof window == 'undefined' || typeof navigator == 'undefined');
};

// whether is in Node
utils.isNode = function() {
  return !(typeof process == 'undefined' || !process.platform || !process.versions);
};

// whether is NW.js (Node-webkit)
utils.isNW = function() {
  var isNode = utils.isNode();
  return isNode && !(typeof global == 'undefined' || !global.gui || !global.gui.Menu);
};

// whether is NW.js (Node-webkit)
utils.isElectron = function() {
  var isNode = utils.isNode();
  return isNode && !(typeof global == 'undefined' || !process.versions.electron);
};

// return min ~ max number
utils.rangeNumber = function(num, min, max) {
  return num > max ? max : num < min ? min : num;
};

module.exports = utils;
<commit_msg>fix invalid detectation is NW.js<commit_after>
var utils = {};

// whether is browser
utils.isBrowser = function() {
  var isElectron = utils.isElectron();
  var isNW = utils.isNW();
  return !isElectron && !isNW && !(typeof window == 'undefined' || typeof navigator == 'undefined');
};

// whether is Node
utils.isNode = function() {
  return !(typeof process == 'undefined' || !process.platform || !process.versions);
};

// whether is NW.js (Node-webkit)
utils.isNW = function() {
  var isNode = utils.isNode();
  return isNode && !(typeof global == 'undefined' || !process.__node_webkit || !process.versions['node-webkit']);
};

// whether is Electron
utils.isElectron = function() {
  var isNode = utils.isNode();
  return isNode && !(typeof global == 'undefined' || !process.versions.electron);
};

// return a number between 'min' and 'max'
utils.rangeNumber = function(num, min, max) {
  return num > max ? max : num < min ? min : num;
};

// get image format
utils.getImageFormat = function(str) {
  var format = str.substr(str.lastIndexOf('.') + 1, str.length);
  format = format === 'jpg' ? 'jpeg' : format;
  return 'image/' + format;
};

// uppercase first letter
utils.upperCaseFirstLetter = function(str) {
  return str.replace(str.charAt(0), function(a) {
    return a.toUpperCase();
  });
};

module.exports = utils;
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert');
var posthtml = require('posthtml');
var posthtmlPrefixClass = require('../index.js');

var input = '

';

function test(input, expected, options) {
    return posthtml()
        .use(posthtmlPrefixClass(options))
        .process(input)
        .then(function(output) {
            assert.equal(output.html, expected);
        });
}

describe('posthtml-prefix-class', function () {
    it('posthtmlPrefixClass()', function () {
        test(
            input,
            input
        );
    });

    it('posthtmlPrefixClass({ prefix: String })', function () {
        test(
            input,
            '

',
            { prefix: 'prefix-' }
        );
    });

    it('posthtmlPrefixClass({ prefix: String, ignore: String })', function () {
        test(
            input,
            '

',
            { prefix: 'prefix-', ignore: 'selector-2' }
        );
    });

    it('posthtmlPrefixClass({ prefix: String, ignore: *String })', function () {
        test(
            input,
            '

',
            { prefix: 'prefix-', ignore: '*-2' }
        );
    });

    it('posthtmlPrefixClass({ prefix: String, ignore: Array })', function () {
        test(
            input,
            input,
            { prefix: 'prefix-', ignore: ['selector-1', 'selector-2'] }
        );
    });

    it('posthtmlPrefixClass({ prefix: String, ignore: *Array })', function () {
        test(
            input,
            input,
            { prefix: 'prefix-', ignore: ['*-1', '*-2'] }
        );
    });
});
<commit_msg>Wait for assertion to resolve before completing test<commit_after>'use strict';

var assert = require('assert');
var posthtml = require('posthtml');
var posthtmlPrefixClass = require('../index.js');

var input = '

';

function test(input, expected, options) {
    return posthtml()
        .use(posthtmlPrefixClass(options))
        .process(input)
        .then(function(output) {
            assert.equal(output.html, expected);
        });
}

describe('posthtml-prefix-class', function () {
    it('posthtmlPrefixClass()', function () {
        return test(
            input,
            input
        );
    });

    it('posthtmlPrefixClass({ prefix: String })', function () {
        return test(
            input,
            '

',
            { prefix: 'prefix-' }
        );
    });

    it('posthtmlPrefixClass({ prefix: String, ignore: String })', function () {
        return test(
            input,
            '

',
            { prefix: 'prefix-', ignore: 'selector-2' }
        );
    });

    it('posthtmlPrefixClass({ prefix: String, ignore: *String })', function () {
        return test(
            input,
            '

',
            { prefix: 'prefix-', ignore: '*-2' }
        );
    });

    it('posthtmlPrefixClass({ prefix: String, ignore: Array })', function () {
        return test(
            input,
            input,
            { prefix: 'prefix-', ignore: ['selector-1', 'selector-2'] }
        );
    });

    it('posthtmlPrefixClass({ prefix: String, ignore: *Array })', function () {
        return test(
            input,
            input,
            { prefix: 'prefix-', ignore: ['*-1', '*-2'] }
        );
    });
});
<|endoftext|>


<commit_before>'use strict';

angular.module('core').controller('HomeController', ['$scope', 'Authentication',
	function($scope, Authentication) {
		// This provides Authentication context.
		$scope.authentication = Authentication;
	}
]);<commit_msg>Add carrousel to home page<commit_after>'use strict';

angular.module('core').controller('HomeController', ['$scope', 'Authentication',
	function($scope, Authentication) {
		// This provides Authentication context.
		$scope.authentication = Authentication;

        $scope.myInterval = 5000;
        var slides = $scope.slides = [];
        $scope.addSlide = function() {
            var newWidth = 600 + slides.length;
            slides.push({
                image: 'http://placekitten.com/' + newWidth + '/300',
                text: ['More','Extra','Lots of','Surplus'][slides.length % 4] + ' ' +
                    ['Cats', 'Kittys', 'Felines', 'Cutes'][slides.length % 4]
            });
        };
        for (var i=0; i<4; i++) {
            $scope.addSlide();
        }
	}
]);<|endoftext|>


<commit_before>// ink.js
// This file contains the code to interact with the Windows Runtime Inking APIs

// This global variable holds a reference to the div that is imposed on top of selected ink.
// It is used to register event handlers that allow the user to move around selected ink.
var selBox;
var attrs;
var manager;

function InkManager(canvas) {
    this.isWRT = typeof Windows != 'undefined';
    manager = this.isWRT
        ? new Windows.UI.Input.Inking.InkManager
        : new SignaturePad(canvas);

    this.manager = manager;
    if (this.isWRT) {
        attrs = new Windows.UI.Input.Inking.InkDrawingAttributes;
        var stroke = attrs.size;
        var context = canvas.getContext('2d');

        attrs.size = stroke;
        attrs.color = Windows.UI.Colors.black;
        attrs.fitToCurve = true;
        stroke.width = stroke.height = context.lineWidth;

        manager.attrs = attrs;
        manager.mode = Windows.UI.Input.Inking.InkManipulationMode.inking;
        manager.setDefaultDrawingAttributes(attrs);

        this.getRecognitionResults = manager.getRecognitionResults.bind(manager);
        this.getStrokes = manager.getStrokes.bind(manager);
        this.processPointerDown = manager.processPointerDown.bind(manager);
        this.processPointerUpdate = manager.processPointerUpdate.bind(manager);
        this.processPointerUp = manager.processPointerUp.bind(manager);
        this.selectWithLine = manager.selectWithLine.bind(manager);
    }
}

InkManager.prototype = {
    getRecognitionResults: function() { return []; },
    getStrokes: function() { return []; },
    processPointerDown: function() {},
    processPointerUpdate: function() {},
    processPointerUp: function() {},
    selectWithLine: function() {},
    set color(value) {
        if (this.isWRT) {
            this._color = value;
        } else {
            this.manager.penColor = value;
        }
    },
    get color() {
        return this.isWRT ? this._color : this.manager.penColor;
    }
};

// Setup the application.
document.addEventListener('DOMContentLoaded', function () {
    // helper functions

    // Set the color (and alpha) of a stroke.  Return true if we actually changed it.
    // Note that we cannot just set the color in stroke.drawingAttributes.color.
    // The stroke API supports get and put operations for drawingAttributes,
    // but we must execute those operations separately, and change any values
    // inside drawingAttributes between those operations.
    function colorStroke(stroke, color) {
        var att = stroke.drawingAttributes;
        var clr = toColorStruct(color);
        if (att.color !== clr) {
            att.color = clr;
            stroke.drawingAttributes = att;
            return true;
        } else {
            return false;
        }
    }

    // Check to see if input is inside of the Canvas for drawing
    function inRect(x, y, rect) {
        return ((rect.x <= x) && (x < (rect.x + rect.width)) &&
                (rect.y <= y) && (y < (rect.y + rect.height)));
    }

    function handleSelectionBoxPointerDown(evt) {
        // Start the processing of events related to this pointer as part of a gesture.
        // In this sample we are interested in MSGestureChange event, which we use to move selected ink.
        // See handleSelectionBoxGestureChange event handler.
        selBox.gestureObject.addPointer(evt.pointerId);
    }

    function handleSelectionBoxGestureChange(evt) {
        // Move selection box
        selBox.rect.x += evt.translationX;
        selBox.rect.y += evt.translationY;
        selBox.style.left = selBox.rect.x + "px";
        selBox.style.top = selBox.rect.y + "px";

        // Move selected ink
        inkManager.moveSelected({ x: evt.translationX, y: evt.translationY });

        renderAllStrokes();
    }

    // Change the color and width in the default (used for new strokes) to the values
    // currently set in the current context.
    function setDefaults() {

        var strokeSize = attrs.size;
        strokeSize.width = strokeSize.height = context.lineWidth;
        attrs.size = strokeSize;
        attrs.color = hexStrToRGBA(context.strokeStyle);
        //attrs.drawAsHighlighter = context === hlContext;
        manager.setDefaultDrawingAttributes(attrs);
    }

    // Test the array of results bounding boxes
    // Draws a single stroke into a specified canvas 2D context, with a specified color and width.
    function renderStroke(stroke, color, width, ctx) {
        ctx.save();
        ctx.beginPath();
        ctx.strokeStyle = color;
        ctx.lineWidth = width;

        console.log('renderStroke: rgb color: r = ' + color.r + ' g = ' + color.g + ' b = ' + color.b);
        var first = true;
        stroke.getRenderingSegments().forEach(function (segment) {
            if (first) {
                ctx.moveTo(segment.position.x, segment.position.y);
                first = false;
            } else {
                ctx.bezierCurveTo(segment.bezierControlPoint1.x, segment.bezierControlPoint1.y,
                                    segment.bezierControlPoint2.x, segment.bezierControlPoint2.y,
                                    segment.position.x, segment.position.y);
            }
        });

        ctx.stroke();
        ctx.closePath();
        ctx.restore();
    }

    function hitTest(tx, ty) {
        var results = inkManager.getRecognitionResults();
        var cWords = results.size;
        if (cWords === 0) {
            return null;
        }
        for (var i = 0; i < cWords; i++) {
            var rect = results[i].boundingRect;
            if (inRect(tx, ty, rect)) {
                return {
                    index: i,
                    handleX: tx,  // Original touch point
                    handleY: ty,
                    strokes: results[i].getStrokes(),
                    rect: rect,
                    alternates: results[i].getTextCandidates()
                };
            }
        }
        return null;
    }

    // Tests the array of results bounding box
    function renderAllStrokes() {
        // Clear the last context
        ink.draw.context.clearRect(0, 0, inkCanvas.width, inkCanvas.height);

        // Get all the strokes from the InkManager
        inkManager.getStrokes().forEach(function (stroke) {
            var att = stroke.drawingAttributes;
            var color = toColorString(att.color);
            var strokeSize = att.size;
            var width = strokeSize.width;
            var ctx = ink.draw.context;
            renderStroke(stroke, color, width, ctx);

        });
    }

    // Convenience function used by color converters.
    function byteHex(num) {
        var hex = num.toString(16);
        if (hex.length === 1) {
            hex = "0" + hex;
        }
        return hex;
    }

    function toColorString(color) {
        return "#" + byteHex(color.r) + byteHex(color.g) + byteHex(color.b);
    }

    function handleColorChange(evt) {
        inkManager.color = evt.srcElement.value;
    }

    // Handle Pointer events
    // We will accept pen down or mouse left down as the start of a stroke.
    // We will accept touch down or mouse right down as the start of a touch.
    function handlePointerDown(evt) {
        if ((evt.pointerType === "pen") || ((evt.pointerType === "mouse") && (evt.button === 0)) || (evt.pointerType === "touch")) {
            // Anchor and clear any current selection.
            //anchorSelection();
            var pt = { x: 0.0, y: 0.0 };
            inkManager.selectWithLine(pt, pt);

            //clearButtonMenus();

            pt = evt.currentPoint;

            if (pt.properties.isEraser) { // The back side of a pen, which we treat as an eraser
                tempEraseMode();
            } else {
                //restoreMode();
            }

            context.beginPath();
            context.moveTo(pt.rawPosition.x, pt.rawPosition.y);

            var pressureWidth = evt.pressure * 15;
            ink.draw.context.lineWidth = pressureWidth;
            setDefaults();

            inkManager.processPointerDown(pt);
            penID = evt.pointerId;
        } else if (evt.pointerType === 'touch') {
            // Start the processing of events related to this pointer as part of a gesture.
            // In this sample we are interested in MSGestureTap event, which we use to show alternates. See handleTap event handler.
            ink.draw.canvas.gestureObject.addPointer(evt.pointerId);
        }
    }

    function handlePointerMove(evt) {
        if (evt.pointerId === penID) {
            var pt = evt.currentPoint;
            context.lineTo(pt.rawPosition.x, pt.rawPosition.y);
            context.stroke();
            // Get all the points we missed and feed them to inkManager.
            // The array pts has the oldest point in position length-1; the most recent point is in position 0.
            // Actually, the point in position 0 is the same as the point in pt above (returned by evt.currentPoint).
            var pts = evt.intermediatePoints;
            for (var i = pts.length - 1; i >= 0 ; i--) {
                inkManager.processPointerUpdate(pts[i]);
            }
        }
    }

    function handlePointerUp(evt) {
        if (evt.pointerId === penID) {
            penID = -1;
            var pt = evt.currentPoint;
            context.strokeStyle = inkManager.color;
            context.lineTo(pt.rawPosition.x, pt.rawPosition.y);
            context.stroke();
            context.closePath();

            var rect = inkManager.processPointerUp(pt);
            if (inkManager.mode === Windows.UI.Input.Inking.InkManipulationMode.selecting) {
                detachSelection(rect);
            }
            renderAllStrokes();
        }
    }

    // We treat the event of the pen leaving the canvas as the same as the pen lifting;
    // it completes the stroke.
    function handlePointerOut(evt) {
        if (evt.pointerId === penID) {
            var pt = evt.currentPoint;
            context.lineTo(pt.rawPosition.x, pt.rawPosition.y);
            context.stroke();
            context.closePath();
            inkManager.processPointerUp(pt);
            penID = -1;
            renderAllStrokes();
        }
    }

    var penID = -1;

    // Create a global object for managing canvases
    var ink = {
        draw:{
            canvas: null,
            context: null
        }
    };

    var canvas = document.getElementById('inkCanvas');
    var context = canvas.getContext('2d');
    var inputColor = document.getElementById('inputColor');

    canvas.setAttribute('width', inkCanvas.offsetWidth);
    canvas.setAttribute('height', inkCanvas.offsetHeight);

    context.lineWidth = 5;
    context.lineCap = 'round';
    context.lineJoin = 'round';

    ink.draw.canvas = canvas;
    ink.draw.context = context;

    var inkManager = new InkManager(canvas);
    inkManager.color = inputColor.value;

    // Initialize the drawing canvas
    canvas.gestureObject = inkManager.isWRT ? new MSGesture : {};
    canvas.gestureObject.target = ink.draw.canvas;

    // Listeners.
    canvas.addEventListener('pointerdown', handlePointerDown);
    canvas.addEventListener('pointerup', handlePointerUp);
    canvas.addEventListener('pointermove', handlePointerMove);
    canvas.addEventListener('pointerout', handlePointerOut);
    inputColor.addEventListener('change', handleColorChange);
});
<commit_msg>Remove dead code.<commit_after>// ink.js
// This file contains the code to interact with the Windows Runtime Inking APIs

// This global variable holds a reference to the div that is imposed on top of selected ink.
// It is used to register event handlers that allow the user to move around selected ink.
function InkManager(canvas) {
    this.isWRT = typeof Windows != 'undefined';
    var context = canvas.getContext('2d');
    var manager = this.isWRT
        ? new Windows.UI.Input.Inking.InkManager
        : new SignaturePad(canvas);

    this.manager = manager;
    this.context = canvas;
    if (this.isWRT) {
        attrs = new Windows.UI.Input.Inking.InkDrawingAttributes;
        var stroke = attrs.size;
        var context = canvas.getContext('2d');

        attrs.size = stroke;
        attrs.color = Windows.UI.Colors.black;
        attrs.fitToCurve = true;
        stroke.width = stroke.height = context.lineWidth;

        manager.attrs = attrs;
        manager.mode = Windows.UI.Input.Inking.InkManipulationMode.inking;
        manager.setDefaultDrawingAttributes(attrs);

        this.getRecognitionResults = manager.getRecognitionResults.bind(manager);
        this.getStrokes = manager.getStrokes.bind(manager);
        this.processPointerDown = manager.processPointerDown.bind(manager);
        this.processPointerUpdate = manager.processPointerUpdate.bind(manager);
        this.processPointerUp = manager.processPointerUp.bind(manager);
        this.selectWithLine = manager.selectWithLine.bind(manager);
    }
}

InkManager.prototype = {
    getRecognitionResults: function() { return []; },
    getStrokes: function() { return []; },
    processPointerDown: function() {},
    processPointerUpdate: function() {},
    processPointerUp: function() {},
    selectWithLine: function() {},
    set color(value) {
        if (this.isWRT) {
            this._color = value;
        } else {
            this.manager.penColor = value;
        }
    },
    get color() {
        return this.isWRT ? this._color : this.manager.penColor;
    },

    // Change the color and width in the default (used for new strokes) to the values
    // currently set in the current context.
    setDefaults: function() {
        var manager = this.manager;
        var attr = manager.attrs;
        var context = manager.context;
        var strokeSize = attrs.size;
        strokeSize.width = strokeSize.height = context.lineWidth;
        attrs.size = strokeSize;
        attrs.color = hexStrToRGBA(context.strokeStyle);
        //attrs.drawAsHighlighter = context === hlContext;
        manager.setDefaultDrawingAttributes(attrs);
    }
};

// Setup the application.
document.addEventListener('DOMContentLoaded', function () {
    // helper functions

    // Check to see if input is inside of the Canvas for drawing
    function inRect(x, y, rect) {
        return ((rect.x <= x) && (x < (rect.x + rect.width)) &&
                (rect.y <= y) && (y < (rect.y + rect.height)));
    }

    // Test the array of results bounding boxes
    // Draws a single stroke into a specified canvas 2D context, with a specified color and width.
    function renderStroke(stroke, color, width, ctx) {
        ctx.save();
        ctx.beginPath();
        ctx.strokeStyle = color;
        ctx.lineWidth = width;

        console.log('renderStroke: rgb color: r = ' + color.r + ' g = ' + color.g + ' b = ' + color.b);
        var first = true;
        stroke.getRenderingSegments().forEach(function (segment) {
            if (first) {
                ctx.moveTo(segment.position.x, segment.position.y);
                first = false;
            } else {
                ctx.bezierCurveTo(segment.bezierControlPoint1.x, segment.bezierControlPoint1.y,
                                    segment.bezierControlPoint2.x, segment.bezierControlPoint2.y,
                                    segment.position.x, segment.position.y);
            }
        });

        ctx.stroke();
        ctx.closePath();
        ctx.restore();
    }

    // Tests the array of results bounding box
    function renderAllStrokes() {
        // Clear the last context
        ink.draw.context.clearRect(0, 0, inkCanvas.width, inkCanvas.height);

        // Get all the strokes from the InkManager
        inkManager.getStrokes().forEach(function (stroke) {
            var att = stroke.drawingAttributes;
            var color = toColorString(att.color);
            var strokeSize = att.size;
            var width = strokeSize.width;
            var ctx = ink.draw.context;
            renderStroke(stroke, color, width, ctx);

        });
    }

    // Convenience function used by color converters.
    function byteHex(num) {
        var hex = num.toString(16);
        if (hex.length === 1) {
            hex = "0" + hex;
        }
        return hex;
    }

    function toColorString(color) {
        return "#" + byteHex(color.r) + byteHex(color.g) + byteHex(color.b);
    }

    function handleColorChange(evt) {
        inkManager.color = evt.srcElement.value;
    }

    // Handle Pointer events
    // We will accept pen down or mouse left down as the start of a stroke.
    // We will accept touch down or mouse right down as the start of a touch.
    function handlePointerDown(evt) {
        if ((evt.pointerType === "pen") || ((evt.pointerType === "mouse") && (evt.button === 0)) || (evt.pointerType === "touch")) {
            // Anchor and clear any current selection.
            //anchorSelection();
            var pt = { x: 0.0, y: 0.0 };
            inkManager.selectWithLine(pt, pt);

            //clearButtonMenus();

            pt = evt.currentPoint;

            if (pt.properties.isEraser) { // The back side of a pen, which we treat as an eraser
                tempEraseMode();
            } else {
                //restoreMode();
            }

            context.beginPath();
            context.moveTo(pt.rawPosition.x, pt.rawPosition.y);

            var pressureWidth = evt.pressure * 15;
            ink.draw.context.lineWidth = pressureWidth;
            inkManager.setDefaults();

            inkManager.processPointerDown(pt);
            penID = evt.pointerId;
        } else if (evt.pointerType === 'touch') {
            // Start the processing of events related to this pointer as part of a gesture.
            // In this sample we are interested in MSGestureTap event, which we use to show alternates. See handleTap event handler.
            ink.draw.canvas.gestureObject.addPointer(evt.pointerId);
        }
    }

    function handlePointerMove(evt) {
        if (evt.pointerId === penID) {
            var pt = evt.currentPoint;
            context.lineTo(pt.rawPosition.x, pt.rawPosition.y);
            context.stroke();
            // Get all the points we missed and feed them to inkManager.
            // The array pts has the oldest point in position length-1; the most recent point is in position 0.
            // Actually, the point in position 0 is the same as the point in pt above (returned by evt.currentPoint).
            var pts = evt.intermediatePoints;
            for (var i = pts.length - 1; i >= 0 ; i--) {
                inkManager.processPointerUpdate(pts[i]);
            }
        }
    }

    function handlePointerUp(evt) {
        if (evt.pointerId === penID) {
            penID = -1;
            var pt = evt.currentPoint;
            context.strokeStyle = inkManager.color;
            context.lineTo(pt.rawPosition.x, pt.rawPosition.y);
            context.stroke();
            context.closePath();

            var rect = inkManager.processPointerUp(pt);
            if (inkManager.mode === Windows.UI.Input.Inking.InkManipulationMode.selecting) {
                detachSelection(rect);
            }
            renderAllStrokes();
        }
    }

    // We treat the event of the pen leaving the canvas as the same as the pen lifting;
    // it completes the stroke.
    function handlePointerOut(evt) {
        if (evt.pointerId === penID) {
            var pt = evt.currentPoint;
            context.lineTo(pt.rawPosition.x, pt.rawPosition.y);
            context.stroke();
            context.closePath();
            inkManager.processPointerUp(pt);
            penID = -1;
            renderAllStrokes();
        }
    }

    var penID = -1;

    // Create a object for managing canvases
    var ink = {
        draw:{
            canvas: null,
            context: null
        }
    };

    var canvas = document.getElementById('inkCanvas');
    var context = canvas.getContext('2d');
    var inputColor = document.getElementById('inputColor');

    canvas.setAttribute('width', inkCanvas.offsetWidth);
    canvas.setAttribute('height', inkCanvas.offsetHeight);

    context.lineWidth = 5;
    context.lineCap = 'round';
    context.lineJoin = 'round';

    ink.draw.canvas = canvas;
    ink.draw.context = context;

    var inkManager = new InkManager(canvas);
    inkManager.color = inputColor.value;

    // Initialize the drawing canvas
    canvas.gestureObject = inkManager.isWRT ? new MSGesture : {};
    canvas.gestureObject.target = ink.draw.canvas;

    // Listeners.
    canvas.addEventListener('pointerdown', handlePointerDown);
    canvas.addEventListener('pointerup', handlePointerUp);
    canvas.addEventListener('pointermove', handlePointerMove);
    canvas.addEventListener('pointerout', handlePointerOut);
    inputColor.addEventListener('change', handleColorChange);
});
<|endoftext|>