<commit_before>var SteamCrypto = require('@doctormckay/steam-crypto');
var Socket = require('net').Socket;
var HTTP = require('http');
var URL = require('url');

module.exports = TCPConnection;

const MAGIC = 'VT01';

require('util').inherits(TCPConnection, require('events').EventEmitter);

/*
 We are expected to implement the following events:
 - packet (a complete message from Steam was received)
 - close (the connection was closed)
 - error (a fatal error occurred, but close will also be emitted)
 - connect (a successful connection was established)
 - end (emitted after close)
 - timeout (emitted after setTimeout elapses)

 We are expected to implement the following methods:
 - end() (request a disconnect)
 - destroy() (immediately kill the connection, without notifying the other side)
 - connect(options) (start connecting to the remote server)
 - port (the port number of the remote host)
 - host (the hostname or IP address of the remote host)
 - localAddress (the local IP we want to bind to, optional)
 - localPort (the local port we want to bind to, optional)
 - send(buffer) (send a raw buffer through the connection, encrypting if necessary)
 - setTimeout(ms[, callback]) (identical to Socket's setTimeout)
 */

/**
 * @constructor
 */
function TCPConnection() {
	// We don't really need to set anything up here
}

TCPConnection.prototype.connect = function(options, callback) {
	if (options.httpProxy) {
		var self = this;
		var url = URL.parse(options.httpProxy);
		url.method = 'CONNECT';
		url.path = options.host + ':' + options.port;
		url.localAddress = options.localAddress;
		url.localPort = options.localPort;

		if (url.auth) {
			url.headers = {"Proxy-Authorization": "Basic " + (new Buffer(url.auth, 'utf8')).toString('base64')};
			delete url.auth;
		}

		var connectionEstablished = false;

		var req = HTTP.request(url);
		req.end();
		req.setTimeout(options.proxyTimeout || 5000);

		req.on('connect', function(res, socket) {
			if (connectionEstablished) {
				socket.end();
				return;
			}

			connectionEstablished = true;
			req.setTimeout(0);

			if (res.statusCode != 200) {
				callback(new Error("HTTP CONNECT " + res.statusCode + " " + res.statusMessage));
				return;
			}

			self._stream = socket;
			self._setupStream();
			callback();
			self.emit('connect');
		});

		req.on('timeout', function() {
			connectionEstablished = true;
			callback(new Error("Proxy connection timed out"));
		});

		req.on('error', function() {
			if (!connectionEstablished) {
				callback.apply(self, Array.prototype.slice.call(arguments));
			}

			self.emit.apply(self, ['error'].concat(Array.prototype.slice.call(arguments)));
			connectionEstablished = true;
		});
	} else {
		this._stream = new Socket();
		this._setupStream();
		callback();
		this._stream.connect(options);
	}
};

TCPConnection.prototype._setupStream = function() {
	var self = this;
	this._stream.on('readable', this._readPacket.bind(this));
	this._stream.on('close', function() { self.emit.apply(self, ['close'].concat(Array.prototype.slice.call(arguments))); });
	this._stream.on('error', function() { self.emit.apply(self, ['error'].concat(Array.prototype.slice.call(arguments))); });
	this._stream.on('connect', function() { self.emit.apply(self, ['connect'].concat(Array.prototype.slice.call(arguments))); });
	this._stream.on('end', function() { self.emit.apply(self, ['end'].concat(Array.prototype.slice.call(arguments))); });
	this._stream.on('timeout', function() { self.emit.apply(self, ['timeout'].concat(Array.prototype.slice.call(arguments))); });
	this.setTimeout = this._stream.setTimeout;
};

TCPConnection.prototype.end = function() {
	if (this._stream) {
		this._stream.end();
	}
};

TCPConnection.prototype.destroy = function() {
	if (this._stream) {
		this._stream.destroy();
	}
};

/**
 * Send data over the connection.
 * @param {Buffer} data
 */
TCPConnection.prototype.send = function(data) {
	// encrypt
	if (this.sessionKey) {
		if (this.useHmac) {
			data = SteamCrypto.symmetricEncryptWithHmacIv(data, this.sessionKey);
		} else {
			data = SteamCrypto.symmetricEncrypt(data, this.sessionKey);
		}
	}

	var buffer = new Buffer(4 + 4 + data.length);
	buffer.writeUInt32LE(data.length, 0);
	buffer.write(MAGIC, 4);
	data.copy(buffer, 8);
	this._stream.write(buffer);
};

TCPConnection.prototype._readPacket = function() {
	if (!this._packetLen) {
		var header = this._stream.read(8);
		if (!header) {
			return;
		}
		this._packetLen = header.readUInt32LE(0);
		if (header.slice(4).toString('ascii') != MAGIC) {
			this.emit('error', new Error('Bad magic'));
			this.end();
			return;
		}
	}

	var packet = this._stream.read(this._packetLen);

	if (!packet) {
		this.emit('debug', 'incomplete packet');
		return;
	}

	delete this._packetLen;

	// decrypt
	if (this.sessionKey) {
		try {
			packet = SteamCrypto.symmetricDecrypt(packet, this.sessionKey, this.useHmac);
		} catch (ex) {
			this.emit('encryptionError', ex);
			return;
		}
	}

	this.emit('packet', packet);

	// keep reading until there's nothing left
	this._readPacket();
};
<commit_msg>Don't also emit apply if we're calling the connect callback<commit_after>var SteamCrypto = require('@doctormckay/steam-crypto');
var Socket = require('net').Socket;
var HTTP = require('http');
var URL = require('url');

module.exports = TCPConnection;

const MAGIC = 'VT01';

require('util').inherits(TCPConnection, require('events').EventEmitter);

/*
 We are expected to implement the following events:
 - packet (a complete message from Steam was received)
 - close (the connection was closed)
 - error (a fatal error occurred, but close will also be emitted)
 - connect (a successful connection was established)
 - end (emitted after close)
 - timeout (emitted after setTimeout elapses)

 We are expected to implement the following methods:
 - end() (request a disconnect)
 - destroy() (immediately kill the connection, without notifying the other side)
 - connect(options) (start connecting to the remote server)
 - port (the port number of the remote host)
 - host (the hostname or IP address of the remote host)
 - localAddress (the local IP we want to bind to, optional)
 - localPort (the local port we want to bind to, optional)
 - send(buffer) (send a raw buffer through the connection, encrypting if necessary)
 - setTimeout(ms[, callback]) (identical to Socket's setTimeout)
 */

/**
 * @constructor
 */
function TCPConnection() {
	// We don't really need to set anything up here
}

TCPConnection.prototype.connect = function(options, callback) {
	if (options.httpProxy) {
		var self = this;
		var url = URL.parse(options.httpProxy);
		url.method = 'CONNECT';
		url.path = options.host + ':' + options.port;
		url.localAddress = options.localAddress;
		url.localPort = options.localPort;

		if (url.auth) {
			url.headers = {"Proxy-Authorization": "Basic " + (new Buffer(url.auth, 'utf8')).toString('base64')};
			delete url.auth;
		}

		var connectionEstablished = false;

		var req = HTTP.request(url);
		req.end();
		req.setTimeout(options.proxyTimeout || 5000);

		req.on('connect', function(res, socket) {
			if (connectionEstablished) {
				socket.end();
				return;
			}

			connectionEstablished = true;
			req.setTimeout(0);

			if (res.statusCode != 200) {
				callback(new Error("HTTP CONNECT " + res.statusCode + " " + res.statusMessage));
				return;
			}

			self._stream = socket;
			self._setupStream();
			callback();
			self.emit('connect');
		});

		req.on('timeout', function() {
			connectionEstablished = true;
			callback(new Error("Proxy connection timed out"));
		});

		req.on('error', function() {
			if (!connectionEstablished) {
				callback.apply(self, Array.prototype.slice.call(arguments));
				return;
			}

			self.emit.apply(self, ['error'].concat(Array.prototype.slice.call(arguments)));
			connectionEstablished = true;
		});
	} else {
		this._stream = new Socket();
		this._setupStream();
		callback();
		this._stream.connect(options);
	}
};

TCPConnection.prototype._setupStream = function() {
	var self = this;
	this._stream.on('readable', this._readPacket.bind(this));
	this._stream.on('close', function() { self.emit.apply(self, ['close'].concat(Array.prototype.slice.call(arguments))); });
	this._stream.on('error', function() { self.emit.apply(self, ['error'].concat(Array.prototype.slice.call(arguments))); });
	this._stream.on('connect', function() { self.emit.apply(self, ['connect'].concat(Array.prototype.slice.call(arguments))); });
	this._stream.on('end', function() { self.emit.apply(self, ['end'].concat(Array.prototype.slice.call(arguments))); });
	this._stream.on('timeout', function() { self.emit.apply(self, ['timeout'].concat(Array.prototype.slice.call(arguments))); });
	this.setTimeout = this._stream.setTimeout;
};

TCPConnection.prototype.end = function() {
	if (this._stream) {
		this._stream.end();
	}
};

TCPConnection.prototype.destroy = function() {
	if (this._stream) {
		this._stream.destroy();
	}
};

/**
 * Send data over the connection.
 * @param {Buffer} data
 */
TCPConnection.prototype.send = function(data) {
	// encrypt
	if (this.sessionKey) {
		if (this.useHmac) {
			data = SteamCrypto.symmetricEncryptWithHmacIv(data, this.sessionKey);
		} else {
			data = SteamCrypto.symmetricEncrypt(data, this.sessionKey);
		}
	}

	var buffer = new Buffer(4 + 4 + data.length);
	buffer.writeUInt32LE(data.length, 0);
	buffer.write(MAGIC, 4);
	data.copy(buffer, 8);
	this._stream.write(buffer);
};

TCPConnection.prototype._readPacket = function() {
	if (!this._packetLen) {
		var header = this._stream.read(8);
		if (!header) {
			return;
		}
		this._packetLen = header.readUInt32LE(0);
		if (header.slice(4).toString('ascii') != MAGIC) {
			this.emit('error', new Error('Bad magic'));
			this.end();
			return;
		}
	}

	var packet = this._stream.read(this._packetLen);

	if (!packet) {
		this.emit('debug', 'incomplete packet');
		return;
	}

	delete this._packetLen;

	// decrypt
	if (this.sessionKey) {
		try {
			packet = SteamCrypto.symmetricDecrypt(packet, this.sessionKey, this.useHmac);
		} catch (ex) {
			this.emit('encryptionError', ex);
			return;
		}
	}

	this.emit('packet', packet);

	// keep reading until there's nothing left
	this._readPacket();
};
<|endoftext|>


<commit_before>var _ = require('underscore'),
    sys = require('sys'),
    path = require('path'),
    Step = require('step'),
    EventEmitter = require('events').EventEmitter,
    Server = require('./server'),
    sm = new (require('sphericalmercator'));

// Batch tile generation class.
//
// Required `options` keys:
//
// - `filepath` {String} filepath of generated batch.
// - `datasource` {String|Object} datasource for the tile, one of the
//   acceptable datasource formats accepted by the `Tile` class.
// - `storage` {Object} storage backend.
// - `renderer` {Object} render backend.
//
// Optional:
//
// - `batchsize` {Number} number of images/grids to render at a time
// - `bbox` {Array} bounding box coordinates in the order `[w, s, e, n]`.
//    Defaults to [-180,-90,180,90].
// - `minzoom` {Number} minimum zoom level to render (inclusive). Default: 0.
// - `maxzoom` {Number} maximum zoom level to render (inclusive). Defualt: 4.
// - `metadata` {Object} hash of metadata to be written to the mbtiles database
// - `serve` {Object} hash of options passed to the renderer `serve` method.
//
// Events:
//
// - `start` Emitted when batch rendering starts.
// - `write` Emitted after each chunk of `batchsize` has been rendered.
// - `end` Emitted when batch rendering is finished.
// - `error` Emitted if an error occurs.
var Batch = function(options) {
    if (!options) throw new Error('`options` is required.');
    if (!options.filepath) throw new Error('`options.filepath` is required.');
    if (!options.datasource) throw new Error('`options.datasource` is required.');
    if (!options.storage) throw new Error('`options.storage` is required.');
    if (!options.renderer) throw new Error('`options.renderer` is required.');

    _(options).defaults({
        batchsize: 100,
        bbox: [-180,-90,180,90],
        minzoom: 0,
        maxzoom: 4,
        metadata: {},
        serve: {}
    });
    _(options.serve).defaults({
        format: 'png',
        datasource: options.datasource
    });
    _(options.metadata).defaults({
        name: path.basename(options.filepath),
        type: 'baselayer',
        version: '1.0.0',
        description: '',
        format: options.serve.format,
        bounds: options.bbox.join(',')
    });

    this.options = options;
    this.storage = options.storage;
    this.server = new Server(options.renderer);

    // Vars needed for tile calculation/generation.
    this.grid = !!this.options.metadata.formatter;
    this.minzoom = this.options.minzoom;
    this.maxzoom = this.options.maxzoom;
    this.tilesCurrent = 0;
    this.tilesTotal = 0;

    // Precalculate the tile int bounds for each zoom level.
    this.zoomBounds = [];
    for (var z = this.minzoom; z <= this.maxzoom; z++) {
        this.zoomBounds[z] = sm.xyz(this.options.bbox, z, true);
        this.tilesTotal +=
            (this.zoomBounds[z].maxX - this.zoomBounds[z].minX + 1) *
            (this.zoomBounds[z].maxY - this.zoomBounds[z].minY + 1);
    }

    // Validate formatter so that wax does not fail down the line.
    if (this.grid) {
        try {
            eval('this.f = ' + this.options.metadata.formatter);
        } catch (e) {
            throw new Error('`metadata.formatter` is not valid javascript: \n' +
                this.options.metadata.formatter);
        }
    }
};

sys.inherits(Batch, EventEmitter);

// Execute the batch. Calls `callback(err)` upon completion or error.
Batch.prototype.execute = function(callback) {
    var batch = this,
        storage = this.storage,
        resource;
    Step(
        function() {
            var next = this;
            storage.pool(batch.options.filepath).create(function(err, res) {
                if (err) return next(err);
                resource = res;
                next();
            });
        },
        function(err) {
            if (err) throw err;
            storage.store('setup', resource, {}, this);
            batch.timeStart = + new Date();
            batch.emit('start', batch);
        },
        function(err) {
            if (err) throw err;
            storage.store('metadata', resource, batch.options.metadata, this);
        },
        function(err) {
            if (err) throw err;
            batch.render(resource, this);
        },
        function(err) {
            if (err) throw err;
            storage.store('finish', resource, {}, this);
        },
        function(err) {
            // The storage resource is released regardless of whether an error
            // was thrown or not.
            storage.pool(batch.options.filepath).destroy(resource);
            batch.timeEnd = + new Date();
            batch.emit(err ? 'error' : 'end', batch, err);
            callback && callback(err);
        }
    );
};

// Render images and grids and store them for the current batch.
Batch.prototype.render = function(resource, callback) {
    var batch = this;

    var loop = function(err) {
        var tiles = batch.next(batch.options.batchsize);
        if (err || !tiles) return callback(err);
        process.nextTick(function() {
        Step(
            function() {
                var group = this.group();
                for (var i = 0; i < tiles.length; i++) {
                    var options = _({}).extend(
                        batch.options.serve,
                        tiles[i]
                    );
                    batch.server.serve(options, group());
                }
            },
            function(err, renders) {
                if (err) throw err;
                batch.storage.store(
                    'tiles',
                    resource,
                    _(renders).map(function(r, i) {
                        return _({}).extend(tiles[i], {data: r[0]});
                    }),
                    this
                );
            },
            function(err) {
                if (err) throw err;
                if (!batch.grid) return this();
                var group = this.group();
                for (var i = 0; i < tiles.length; i++) {
                    var options = _({}).extend(
                        batch.options.serve,
                        tiles[i],
                        {format: 'grid.json'}
                    );
                    batch.server.serve(options, group());
                }
            },
            function(err, renders) {
                if (err) throw err;
                if (!batch.grid) return this();
                batch.storage.store(
                    'grids',
                    resource,
                    _(renders).map(function(r, i) {
                        return _({}).extend(tiles[i], r[0]);
                    }),
                    this
                );
            },
            function(err) {
                if (err) throw err;
                batch.emit('write', batch);
                this();
            },
            loop
        );
        });
    };
    loop();
};

// Retrieve an array of tiles that should be rendered next. Returns `false` if
// there are no more tiles to be generated.
Batch.prototype.next = function(count) {
    var count = count || 1;
    var triplets = [];

    this.curZ = (typeof this.curZ === 'undefined') ? this.minzoom : this.curZ;
    for (var z = this.curZ; z <= this.maxzoom; z++) {
        this.curX = (typeof this.curX === 'undefined') ?
            this.zoomBounds[z].minX : this.curX;
        this.curY = (typeof this.curY === 'undefined') ?
            this.zoomBounds[z].minY : this.curY;

        for (var x = this.curX; x <= this.zoomBounds[z].maxX; x++) {
            for (var y = this.curY; y <= this.zoomBounds[z].maxY; y++) {
                this.curX = x;
                this.curY = y;
                this.curZ = z;
                if (triplets.length < count) {
                    triplets.push({x: x, y: y, z: z});
                    this.tilesCurrent++;
                } else if (triplets.length === count) {
                    return triplets;
                }
            }
            // End of row, reset Y cursor.
            this.curY = this.zoomBounds[z].minY;
        }

        // End of the zoom layer, pass through and reset XY cursors.
        delete this.curX;
        delete this.curY;
    }
    // We're done, set our cursor outside usable bounds.
    this.curZ = this.maxzoom + 1;
    this.curX = this.zoomBounds[this.maxzoom].maxX + 1;
    this.curY = this.zoomBounds[this.maxzoom].maxY + 1;
    return triplets.length ? triplets : false;
};

module.exports = Batch;
<commit_msg>metatiling support in tilelive.Batch<commit_after>var _ = require('underscore'),
    sys = require('sys'),
    path = require('path'),
    Step = require('step'),
    EventEmitter = require('events').EventEmitter,
    Server = require('./server'),
    sm = new (require('sphericalmercator'));

// Batch tile generation class.
//
// Required `options` keys:
//
// - `filepath` {String} filepath of generated batch.
// - `datasource` {String|Object} datasource for the tile, one of the
//   acceptable datasource formats accepted by the `Tile` class.
// - `storage` {Object} storage backend.
// - `renderer` {Object} render backend.
//
// Optional:
//
// - `batchsize` {Number} number of images/grids to render at a time
// - `bbox` {Array} bounding box coordinates in the order `[w, s, e, n]`.
//    Defaults to [-180,-90,180,90].
// - `minzoom` {Number} minimum zoom level to render (inclusive). Default: 0.
// - `maxzoom` {Number} maximum zoom level to render (inclusive). Defualt: 4.
// - `metadata` {Object} hash of metadata to be written to the mbtiles database
// - `serve` {Object} hash of options passed to the renderer `serve` method.
//
// Events:
//
// - `start` Emitted when batch rendering starts.
// - `write` Emitted after each chunk of `batchsize` has been rendered.
// - `end` Emitted when batch rendering is finished.
// - `error` Emitted if an error occurs.
var Batch = function(options) {
    if (!options) throw new Error('`options` is required.');
    if (!options.filepath) throw new Error('`options.filepath` is required.');
    if (!options.datasource) throw new Error('`options.datasource` is required.');
    if (!options.storage) throw new Error('`options.storage` is required.');
    if (!options.renderer) throw new Error('`options.renderer` is required.');

    _(options).defaults({
        batchsize: 100,
        bbox: [-180,-90,180,90],
        minzoom: 0,
        maxzoom: 4,
        metatile: 1,
        metadata: {},
        serve: {}
    });
    _(options.serve).defaults({
        format: 'png',
        datasource: options.datasource
    });
    _(options.metadata).defaults({
        name: path.basename(options.filepath),
        type: 'baselayer',
        version: '1.0.0',
        description: '',
        format: options.serve.format,
        bounds: options.bbox.join(',')
    });

    this.options = options;
    this.storage = options.storage;
    this.server = new Server(options.renderer);

    // Vars needed for tile calculation/generation.
    this.grid = !!this.options.metadata.formatter;
    this.minzoom = this.options.minzoom;
    this.maxzoom = this.options.maxzoom;
    this.tilesCurrent = 0;
    this.tilesTotal = 0;

    // Precalculate the tile int bounds for each zoom level.
    this.zoomBounds = [];
    for (var z = this.minzoom; z <= this.maxzoom; z++) {
        this.zoomBounds[z] = sm.xyz(this.options.bbox, z, true);
        this.tilesTotal +=
            (this.zoomBounds[z].maxX - this.zoomBounds[z].minX + 1) *
            (this.zoomBounds[z].maxY - this.zoomBounds[z].minY + 1);
    }

    // Validate formatter so that wax does not fail down the line.
    if (this.grid) {
        try {
            eval('this.f = ' + this.options.metadata.formatter);
        } catch (e) {
            throw new Error('`metadata.formatter` is not valid javascript: \n' +
                this.options.metadata.formatter);
        }
    }

    // ensure that the metatile value is a power of 2
    var is_2p = options.metatile && !(options.metatile & (options.metatile - 1));
    if (!is_2p) {
        throw new Error('`metatile` value is not valid "' + options.metatile + '" (it must be a power of 2)');
    }
};

sys.inherits(Batch, EventEmitter);

// Execute the batch. Calls `callback(err)` upon completion or error.
Batch.prototype.execute = function(callback) {
    var batch = this,
        storage = this.storage,
        resource;
    Step(
        function() {
            var next = this;
            storage.pool(batch.options.filepath).create(function(err, res) {
                if (err) return next(err);
                resource = res;
                next();
            });
        },
        function(err) {
            if (err) throw err;
            storage.store('setup', resource, {}, this);
            batch.timeStart = + new Date();
            batch.emit('start', batch);
        },
        function(err) {
            if (err) throw err;
            storage.store('metadata', resource, batch.options.metadata, this);
        },
        function(err) {
            if (err) throw err;
            batch.render(resource, this);
        },
        function(err) {
            if (err) throw err;
            storage.store('finish', resource, {}, this);
        },
        function(err) {
            // The storage resource is released regardless of whether an error
            // was thrown or not.
            storage.pool(batch.options.filepath).destroy(resource);
            batch.timeEnd = + new Date();
            batch.emit(err ? 'error' : 'end', batch, err);
            callback && callback(err);
        }
    );
};

// Render images and grids and store them for the current batch.
Batch.prototype.render = function(resource, callback) {
    var batch = this;

    var loop = function(err) {
        var tiles = batch.next(batch.options.batchsize);
        if (err || !tiles) return callback(err);
        process.nextTick(function() {
        Step(
            function() {
                var group = this.group();
                for (var i = 0; i < tiles.length; i++) {
                    var options = _({}).extend(
                        batch.options.serve,
                        tiles[i]
                    );
                    batch.server.serve(options, group());
                }
            },
            function(err, renders) {
                if (err) throw err;
                if (batch.options.metatile > 1) {
                    var group = this.group();
                      for (var j = 0; j < renders.length; j++) {
                          var render = renders[j];
                          batch.storage.store(
                              'tiles',
                              resource,
                              _(render).map(function(r, i) {
                                  return _({}).extend(r[2], {data: r[0]});
                              }),
                              group()
                          );
                      }
                } else {
                    batch.storage.store(
                        'tiles',
                        resource,
                        _(renders).map(function(r, i) {
                            return _({}).extend(tiles[i], {data: r[0]});
                        }),
                        this
                    );
                }
            },
            function(err) {
                if (err) throw err;
                if (!batch.grid) return this();
                var group = this.group();
                for (var i = 0; i < tiles.length; i++) {
                    var options = _({}).extend(
                        batch.options.serve,
                        tiles[i],
                        {format: 'grid.json'}
                    );
                    batch.server.serve(options, group());
                }
            },
            function(err, renders) {
                if (err) throw err;
                if (!batch.grid) return this();
                if (batch.options.metatile > 1) {
                    var group = this.group();
                      for (var j = 0; j < renders.length; j++) {
                          var render = renders[j];
                          batch.storage.store(
                              'grids',
                              resource,
                              _(render).map(function(r, i) {
                                  return _({}).extend(r[2], r[0] );
                              }),
                              group()
                          );
                      }
                } else {
                    batch.storage.store(
                        'grids',
                        resource,
                        _(renders).map(function(r, i) {
                            return _({}).extend(tiles[i], r[0]);
                        }),
                        this
                    );
                }
            },
            function(err) {
                if (err) throw err;
                batch.emit('write', batch);
                this();
            },
            loop
        );
        });
    };
    loop();
};

// Retrieve an array of tiles that should be rendered next. Returns `false` if
// there are no more tiles to be generated.
Batch.prototype.next = function(count) {
    var count = count || 1;
    var tile_info = [];

    this.curZ = (typeof this.curZ === 'undefined') ? this.minzoom : this.curZ;
    for (var z = this.curZ; z <= this.maxzoom; z++) {

        this.curX = (typeof this.curX === 'undefined') ?
            this.zoomBounds[z].minX : this.curX;

        this.curY = (typeof this.curY === 'undefined') ?
            this.zoomBounds[z].minY : this.curY;

        var metasize = 1;
        if (this.options.metatile > 1)
            metasize = Math.min(this.options.metatile, 1 << z);

        for (var x = this.curX; x <= this.zoomBounds[z].maxX; x=x+metasize) {
            if ((x < 0) || (x >= Math.pow(2,z))) {
               continue;
            }
            for (var y = this.curY; y <= this.zoomBounds[z].maxY; y=y+metasize) {
                if ((y < 0) || (y >= Math.pow(2,z))) {
                   continue;
                }
                this.curX = x;
                this.curY = y;
                this.curZ = z;
                if (tile_info.length < count) {
                    var info = {z: z, x: x, y: y,
                                metatile: this.options.metatile,
                                metasize: metasize };
                    tile_info.push(info);
                    this.tilesCurrent=this.tilesCurrent+(metasize*metasize);
                } else if (tile_info.length === count) {
                    return tile_info;
                }
            }
            // End of row, reset Y cursor.
            this.curY = this.zoomBounds[z].minY;
        }

        // End of the zoom layer, pass through and reset XY cursors.
        delete this.curX;
        delete this.curY;
    }

    // We're done, set our cursor outside usable bounds.
    this.curZ = this.maxzoom + 1;
    this.curX = this.zoomBounds[this.maxzoom].maxX + 1;
    this.curY = this.zoomBounds[this.maxzoom].maxY + 1;
    return tile_info.length ? tile_info : false;
};

module.exports = Batch;
<|endoftext|>


<commit_before>'use strict'

var AbstractTransport = require('./abstract')
var merge = require('merge')
var net = require('net')
var nicAddresses = require('./addresses/nic')
var NetStringStream = require('./session/netstring')
var runtime = require('mm-runtime-info')
var util = require('util')
var winston = require('winston-debug')
var winstonWrapper = require('winston-meta-wrapper')

/**
 * Tcp transport
 *
 * @constructor
 * @fires TcpTransport#active
 * @fires TcpTransport#listening
 * @fires TcpTransport#connection
 * @fires TcpTransport#connect
 * @fires TcpTransport#error
 * @fires TcpTransport#close
 */
function TcpTransport (socketOpts) {
  if (!(this instanceof TcpTransport)) {
    return new TcpTransport(socketOpts)
  }
  AbstractTransport.call(this)
  // verify runtime compatibility
  if (!TcpTransport.isCompatibleWithRuntime()) {
    var errorMsg = 'TCP transport cannot be used on this runtime'
    this._error(errorMsg)
  }
  // logging
  this._log = winstonWrapper(winston)
  this._log.addMeta({
    module: '1tp:transports:tcp'
  })
  // init
  var opts = merge(Object.create(TcpTransport.DEFAULTS), socketOpts)
  this._createServerSocket(opts)
  // done
  this._log.debug('created tcp transport with args ' + JSON.stringify(opts))
}

// Inherit from abstract transport
util.inherits(TcpTransport, AbstractTransport)

TcpTransport.DEFAULTS = {
  allowHalfOpen: false,
  pauseOnConnect: false
}

TcpTransport.isCompatibleWithRuntime = function () {
  return !runtime.isBrowser() && !runtime.isCordovaApp()
}

TcpTransport.prototype._createServerSocket = function (socketOpts) {
  var self = this
  this._muteSocketErrorListeners = false
  this._server = net.createServer(socketOpts)
  this._server.on('connection', this._onConnection())
  this._server.on('error', function (error) {
    if (self._muteSocketErrorListeners) {
      return
    }
    self._log.error(error)
    self._error(error)
  })
}

TcpTransport.prototype._onConnection = function () {
  var self = this
  return function (socket) {
    var netstring = new NetStringStream()
    netstring.attachToEncoder(socket)
    netstring.attachToDecoder(socket)
    var peerConnectionInfo = {
      transportType: self.transportType(),
      transportInfo: {
        address: socket.remoteAddress,
        port: socket.remotePort
      }
    }
    self._fireConnectionEvent(netstring, self, peerConnectionInfo)
  }
}

TcpTransport.prototype.transportType = function () {
  return 'tcp'
}

TcpTransport.prototype.connectTimeout = function () {
  return 100
}

TcpTransport.prototype.listen = function (listeningInfo, onSuccess, onFailure) {
  this._log.debug('listen to ' + JSON.stringify(listeningInfo))
  var port, address
  if (listeningInfo !== undefined) {
    // verify listeningInfo
    if (listeningInfo.transportType !== this.transportType()) {
      var transportTypeError = 'incorrect listeningInfo: unexpected transportType -- ignoring request'
      this._log.error(transportTypeError)
      this._error(transportTypeError, onFailure)
      return
    }
    if (listeningInfo.transportInfo === undefined) {
      var transportInfoUndefined = 'incorrect connectionInfo: transportInfo is undefined'
      this._log.error(transportInfoUndefined)
      this._error(transportInfoUndefined, onFailure)
      return
    }
    port = listeningInfo.transportInfo.port
    address = listeningInfo.transportInfo.address
  }

  var self = this
  // fire up
  port = (port === undefined) ? 0 : port
  // prepare to process errors during bind operation
  var onBindError = function (error) {
    self._error(error, onFailure)
  }
  // mute existing error listeners during bind operation
  this._muteSocketErrorListeners = true
  // register temp error listener
  this._server.once('error', onBindError)
  // bind tcp server socket
  this._server.listen(port, address, function () {
    // drop error listener
    self.removeListener('error', onBindError)
    // unmute existing error listeners
    self._muteSocketErrorListeners = true
    // create connection info
    var myConnectionInfo = {
      transportType: self.transportType(),
      transportInfo: {
        // address will be added below
        port: self._server.address().port
      },
      version: self.version
    }
    // if address was specified in listening info, then reuse it
    if (address) {
      myConnectionInfo.transportInfo.address = self._server.address().address
      self._myConnectionInfo = myConnectionInfo
      self._log.debug('tcp socket bound, connectionInfo = ' + JSON.stringify(myConnectionInfo))
      self._fireListeningEvent(myConnectionInfo, onSuccess)
    } else {
      // otherwise, retrieve local ip address
      nicAddresses.getIpAddressesP()
        .then(function (addresses) {
          var myConnectionInfos = addresses.map(function (localAddress) {
            var connectionInfo = {
              transportType: myConnectionInfo.transportType,
              transportInfo: {
                address: localAddress,
                // INVARIANT thomasdelaet: port numbers must be the same when creating separate transport info instances for different local ipAddresses
                port: myConnectionInfo.transportInfo.port
              },
              version: self.version
            }
            return connectionInfo
          })
          self._log.debug('tcp socket bound, connectionInfo = ' + JSON.stringify(myConnectionInfos))
          self._fireListeningEvent(myConnectionInfos, onSuccess)
        })
        .catch(function (error) {
          self._error(error, onFailure)
        })
    }
  })
}

TcpTransport.prototype.connect = function (peerConnectionInfo, onSuccess, onFailure) {
  this._log.debug('connect to ' + JSON.stringify(peerConnectionInfo))
  // verify peerConnectionInfo
  if (peerConnectionInfo.transportType !== this.transportType()) {
    var transportTypeError = 'incorrect connectionInfo: unexpected transportType -- ignoring request'
    this._log.error(transportTypeError)
    this._error(transportTypeError, onFailure)
    return
  }
  if (peerConnectionInfo.transportInfo === undefined) {
    var transportInfoUndefined = 'incorrect connectionInfo: transportInfo is undefined'
    this._log.error(transportInfoUndefined)
    this._error(transportInfoUndefined, onFailure)
    return
  }
  if (peerConnectionInfo.transportInfo.address === undefined || peerConnectionInfo.transportInfo.port === undefined) {
    var addressError = 'incorrect connectionInfo: address and/or port attribute is undefined'
    this._log.error(addressError)
    this._error(addressError, onFailure)
    return
  }
  // establish connection
  var self = this
  var socket = net.connect(peerConnectionInfo.transportInfo.port, peerConnectionInfo.transportInfo.address, function () {
    var netstring = new NetStringStream()
    netstring.attachToEncoder(socket)
    netstring.attachToDecoder(socket)
    self._fireConnectEvent(netstring, peerConnectionInfo, onSuccess)
  })
  socket.on('error', function (error) {
    self._error(error, onFailure)
  })
}

TcpTransport.prototype.close = function (onSuccess, onFailure) {
  var self = this
  this._server.close(function () {
    self._fireCloseEvent(onSuccess)
  })
}

module.exports = TcpTransport
<commit_msg>added connection timeout + implemented connection abort<commit_after>'use strict'

var AbstractTransport = require('./abstract')
var merge = require('merge')
var net = require('net')
var nicAddresses = require('./addresses/nic')
var NetStringStream = require('./session/netstring')
var runtime = require('mm-runtime-info')
var util = require('util')
var winston = require('winston-debug')
var winstonWrapper = require('winston-meta-wrapper')

/**
 * Tcp transport
 *
 * @constructor
 * @fires TcpTransport#listening
 * @fires TcpTransport#connection
 * @fires TcpTransport#connect
 * @fires TcpTransport#error
 * @fires TcpTransport#close
 */
 function TcpTransport (args) {
   if (!(this instanceof TcpTransport)) {
     return new TcpTransport(args)
   }
   AbstractTransport.call(this)
   // verify runtime compatibility
   if (!TcpTransport.isCompatibleWithRuntime()) {
     var errorMsg = 'TCP transport cannot be used on this runtime'
     this._error(errorMsg)
   }
   // logging
   this._log = winstonWrapper(winston)
   this._log.addMeta({
     module: '1tp:transports:tcp'
   })
   // init
   this._args = merge(Object.create(TcpTransport.DEFAULTS), args)
   this._connectingSockets = {}
   // create listening socket
   this._createServerSocket(this._args)
   // done
   this._log.debug('created tcp transport with args ' + JSON.stringify(this._args))
 }

// Inherit from abstract transport
util.inherits(TcpTransport, AbstractTransport)

TcpTransport.DEFAULTS = {
  allowHalfOpen: false,
  pauseOnConnect: false,
  connectTimeout: 100
}

TcpTransport.isCompatibleWithRuntime = function () {
  return !runtime.isBrowser() && !runtime.isCordovaApp()
}

TcpTransport.prototype._createServerSocket = function (socketOpts) {
  var self = this
  this._muteSocketErrorListeners = false
  this._server = net.createServer(socketOpts)
  this._server.on('connection', this._onConnection())
  this._server.on('error', function (error) {
    if (self._muteSocketErrorListeners) {
      return
    }
    self._log.error(error)
    self._error(error)
  })
}

TcpTransport.prototype._onConnection = function () {
  var self = this
  return function (socket) {
    var netstring = new NetStringStream()
    netstring.attachToEncoder(socket)
    netstring.attachToDecoder(socket)
    var peerConnectionInfo = {
      transportType: self.transportType(),
      transportInfo: {
        address: socket.remoteAddress,
        port: socket.remotePort
      }
    }
    self._fireConnectionEvent(netstring, self, peerConnectionInfo)
  }
}

TcpTransport.prototype.transportType = function () {
  return 'tcp'
}

TcpTransport.prototype.connectTimeout = function () {
  return 100
}

TcpTransport.prototype.listen = function (listeningInfo, onSuccess, onFailure) {
  this._log.debug('listen to ' + JSON.stringify(listeningInfo))
  var port, address
  if (listeningInfo !== undefined) {
    // verify listeningInfo
    if (listeningInfo.transportType !== this.transportType()) {
      var transportTypeError = 'incorrect listeningInfo: unexpected transportType -- ignoring request'
      this._log.error(transportTypeError)
      this._error(transportTypeError, onFailure)
      return
    }
    if (listeningInfo.transportInfo === undefined) {
      var transportInfoUndefined = 'incorrect connectionInfo: transportInfo is undefined'
      this._log.error(transportInfoUndefined)
      this._error(transportInfoUndefined, onFailure)
      return
    }
    port = listeningInfo.transportInfo.port
    address = listeningInfo.transportInfo.address
  }

  var self = this
  // fire up
  port = (port === undefined) ? 0 : port
  // prepare to process errors during bind operation
  var onBindError = function (error) {
    self._error(error, onFailure)
  }
  // mute existing error listeners during bind operation
  this._muteSocketErrorListeners = true
  // register temp error listener
  this._server.once('error', onBindError)
  // bind tcp server socket
  this._server.listen(port, address, function () {
    // drop error listener
    self.removeListener('error', onBindError)
    // unmute existing error listeners
    self._muteSocketErrorListeners = true
    // create connection info
    var myConnectionInfo = {
      transportType: self.transportType(),
      transportInfo: {
        // address will be added below
        port: self._server.address().port
      },
      version: self.version
    }
    // if address was specified in listening info, then reuse it
    if (address) {
      myConnectionInfo.transportInfo.address = self._server.address().address
      self._myConnectionInfo = myConnectionInfo
      self._log.debug('tcp socket bound, connectionInfo = ' + JSON.stringify(myConnectionInfo))
      self._fireListeningEvent(myConnectionInfo, onSuccess)
    } else {
      // otherwise, retrieve local ip address
      nicAddresses.getIpAddressesP()
        .then(function (addresses) {
          var myConnectionInfos = addresses.map(function (localAddress) {
            var connectionInfo = {
              transportType: myConnectionInfo.transportType,
              transportInfo: {
                address: localAddress,
                // INVARIANT thomasdelaet: port numbers must be the same when creating separate transport info instances for different local ipAddresses
                port: myConnectionInfo.transportInfo.port
              },
              version: self.version
            }
            return connectionInfo
          })
          self._log.debug('tcp socket bound, connectionInfo = ' + JSON.stringify(myConnectionInfos))
          self._fireListeningEvent(myConnectionInfos, onSuccess)
        })
        .catch(function (error) {
          self._error(error, onFailure)
        })
    }
  })
}

TcpTransport.prototype.connect = function (peerConnectionInfo, onSuccess, onFailure) {
  this._log.debug('connect to ' + JSON.stringify(peerConnectionInfo))
  // verify peerConnectionInfo
  if (peerConnectionInfo.transportType !== this.transportType()) {
    var transportTypeError = 'incorrect connectionInfo: unexpected transportType -- ignoring request'
    this._log.error(transportTypeError)
    this._error(transportTypeError, onFailure)
    return
  }
  if (peerConnectionInfo.transportInfo === undefined) {
    var transportInfoUndefined = 'incorrect connectionInfo: transportInfo is undefined'
    this._log.error(transportInfoUndefined)
    this._error(transportInfoUndefined, onFailure)
    return
  }
  if (peerConnectionInfo.transportInfo.address === undefined || peerConnectionInfo.transportInfo.port === undefined) {
    var addressError = 'incorrect connectionInfo: address and/or port attribute is undefined'
    this._log.error(addressError)
    this._error(addressError, onFailure)
    return
  }
  // establish connection
  var self = this
  var timeout
  var socket = net.connect(peerConnectionInfo.transportInfo.port, peerConnectionInfo.transportInfo.address, function () {
    // stop timer
    clearTimeout(timeout)
    // delete socket from connectingSockets
    delete self._connectingSockets[peerConnectionInfo.transportInfo]
    // create netstring stream + pipe socket to this stream
    var netstring = new NetStringStream()
    netstring.attachToEncoder(socket)
    netstring.attachToDecoder(socket)
    // fire connect event
    self._fireConnectEvent(netstring, peerConnectionInfo, onSuccess)
  })
  socket.on('error', function (error) {
    self._error(error, onFailure)
  })
  // store socket in case the scheduler wants to abort it
  this._connectingSockets[peerConnectionInfo.transportInfo] = socket
  // set timeout
  timeout = setTimeout(function () {
    var connectionTimeoutError = 'connection timeout'
    // abort handshake init
    self.abort(peerConnectionInfo)
    // fire error event
    self._error(connectionTimeoutError, onFailure)
  }, this._args.connectTimeout)
}

TcpTransport.prototype.abort = function (peerConnectionInfo, onFailure) {
  this._log.debug('aborting handshake with ' + JSON.stringify(peerConnectionInfo))
  // verify peerConnectionInfo
  if (peerConnectionInfo.transportType !== this.transportType()) {
    var transportTypeError = 'incorrect connectionInfo: unexpected transportType -- Ignoring request'
    this._log.error(transportTypeError)
    this._error(transportTypeError, onFailure)
    return
  }
  if (peerConnectionInfo.transportInfo === undefined) {
    var transportInfoUndefined = 'incorrect connectionInfo: transportInfo is undefined'
    this._log.error(transportInfoUndefined)
    this._error(transportInfoUndefined, onFailure)
    return
  }
  if (peerConnectionInfo.transportInfo.address === undefined || peerConnectionInfo.transportInfo.port === undefined) {
    var addressError = 'incorrect connectionInfo: address and/or port attribute is undefined'
    this._log.error(addressError)
    this._error(addressError, onFailure)
    return
  }
  var socket = this._connectingSockets[peerConnectionInfo.transportInfo]
  if (!socket) {
    var noSocketError = 'cannot find socket for connectionInfo ' + JSON.stringify(peerConnectionInfo.transportInfo)
    this._log.error(noSocketError)
    this._error(noSocketError, onFailure)
    return
  }
  // end socket
  socket.end()
  // delete socket from connectingSockets
  delete this._connectingSockets[peerConnectionInfo.transportInfo]
}

TcpTransport.prototype.close = function (onSuccess, onFailure) {
  var self = this
  this._server.close(function () {
    self._fireCloseEvent(onSuccess)
  })
}

module.exports = TcpTransport
<|endoftext|>


<commit_before>'use strict';
var vow = require('vow'),
    vowFs = require('vow-fs'),
    _ = require('lodash'),
    istanbul = require('istanbul'),
    SourceLocator = require('enb-source-map/lib/source-locator'),

    CoverageObject = require('./coverage-object');

function unmapCoverageObject(sourceObject) {
    var sources = Object.keys(sourceObject);
    return vow.all(sources.map(function (fileName) {
            return vowFs.read(fileName, 'utf8').then(function (source) {
                return unmapFile(fileName, sourceObject[fileName], source);
            });
        }))
        .then(function (coverageObjects) {
            return coverageObjects.reduce(mergeCoverage);
        });
}

function unmapFile(fileName, fileObject, source) {
    var locator = new SourceLocator(fileName, source),
        result = new CoverageObject();

    Object.keys(fileObject.statementMap).forEach(function (key) {
        var statement = fileObject.statementMap[key];

        result.addStatement({
            start: locator.locate(statement.start.line, statement.start.column),
            end: locator.locate(statement.end.line, statement.end.column),
            skip: statement.skip
        }, fileObject.s[key]);
    });

    Object.keys(fileObject.fnMap).forEach(function (key) {
        var fn = fileObject.fnMap[key],
            loc = fn.loc;
        result.addFunction({
            name: fn.name,
            start: locator.locate(loc.start.line, loc.start.column),
            end: locator.locate(loc.end.line, loc.end.column),
            skip: fn.skip
        }, fileObject.f[key]);
    });

    Object.keys(fileObject.branchMap).forEach(function (key) {
        var branch = fileObject.branchMap[key];
        result.addBranch({
            type: branch.type,
            locations: branch.locations.map(function (loc) {
                return {
                    start: locator.locate(loc.start.line, loc.start.column),
                    end: locator.locate(loc.end.line, loc.end.column),
                    skip: loc.skip
                };
            })

        }, fileObject.b[key]);
    });

    return tryToStripSource(result.coverage, fileName);
}

function tryToStripSource(coverage, source) {
    var keys = Object.keys(coverage);
    if (keys.length !== 1 || keys[0] !== source) {
        delete coverage[source];
    }
    return coverage;
}

function mergeCoverage(first, second) {
    var result = _.clone(first);
    _.each(second, function (value, key) {
        if (result[key]) {
            result[key] = istanbul.utils.mergeFileCoverage(result[key], value);
        } else {
            result[key] = value;
        }
    });
    return result;
}

module.exports = unmapCoverageObject;
<commit_msg>Use istanbul.Collector instead of istanbul.utils.mergeFileCoverage<commit_after>'use strict';
var vow = require('vow'),
    vowFs = require('vow-fs'),
    istanbul = require('istanbul'),
    SourceLocator = require('enb-source-map/lib/source-locator'),

    CoverageObject = require('./coverage-object');

function unmapCoverageObject(sourceObject) {
    var sources = Object.keys(sourceObject);
    return vow.all(sources.map(function (fileName) {
            return vowFs.read(fileName, 'utf8').then(function (source) {
                return unmapFile(fileName, sourceObject[fileName], source);
            });
        }))
        .then(mergeCoverage);
}

function unmapFile(fileName, fileObject, source) {
    var locator = new SourceLocator(fileName, source),
        result = new CoverageObject();

    Object.keys(fileObject.statementMap).forEach(function (key) {
        var statement = fileObject.statementMap[key];

        result.addStatement({
            start: locator.locate(statement.start.line, statement.start.column),
            end: locator.locate(statement.end.line, statement.end.column),
            skip: statement.skip
        }, fileObject.s[key]);
    });

    Object.keys(fileObject.fnMap).forEach(function (key) {
        var fn = fileObject.fnMap[key],
            loc = fn.loc;
        result.addFunction({
            name: fn.name,
            start: locator.locate(loc.start.line, loc.start.column),
            end: locator.locate(loc.end.line, loc.end.column),
            skip: fn.skip
        }, fileObject.f[key]);
    });

    Object.keys(fileObject.branchMap).forEach(function (key) {
        var branch = fileObject.branchMap[key];
        result.addBranch({
            type: branch.type,
            locations: branch.locations.map(function (loc) {
                return {
                    start: locator.locate(loc.start.line, loc.start.column),
                    end: locator.locate(loc.end.line, loc.end.column),
                    skip: loc.skip
                };
            })

        }, fileObject.b[key]);
    });

    return tryToStripSource(result.coverage, fileName);
}

function tryToStripSource(coverage, source) {
    var keys = Object.keys(coverage);
    if (keys.length !== 1 || keys[0] !== source) {
        delete coverage[source];
    }
    return coverage;
}

function mergeCoverage(reports) {
    var collector = new istanbul.Collector();
    reports.forEach(function(report) {
        collector.add(report);
    });

    return collector.getFinalCoverage();
}

module.exports = unmapCoverageObject;
<|endoftext|>


<commit_before>import { useState, useEffect, useMemo } from 'haunted';

const hashUrl = () =>
		new URL(
			location.hash.replace(/^#!?/iu, '').replace('%23', '#'),
			location.origin
		),
	parameterize = (hashParam) =>
		hashParam
			? () =>
					new URLSearchParams(hashUrl().hash.replace('#', '')).get(hashParam)
			: undefined;

export const link = (hashParam, value) => {
		if (!hashParam) {
			return;
		}
		const url = hashUrl(),
			sp = new URLSearchParams(url.hash.replace('#', ''));
		sp.set(hashParam, value);
		return (
			'#!' + Object.assign(url, { hash: sp }).href.replace(location.origin, '')
		);
	},
	useHashParam = (hashParam) => {
		const parameterized = useMemo(() => parameterize(hashParam), [hashParam]),
			[param, setParam] = useState(parameterized);

		useEffect(() => {
			if (parameterized == null) {
				return;
			}
			const readParam = () =>
				requestAnimationFrame(() => setParam(parameterized));
			readParam();
			window.addEventListener('popstate', readParam);
			window.addEventListener('hashchange', readParam);
			return () => {
				window.removeEventListener('popstate', readParam);
				window.removeEventListener('hashchange', readParam);
			};
		}, [parameterized]);

		const set = useMemo(
			() =>
				hashParam
					? (v) => {
							setParam(v);
							history.pushState({}, '', link(hashParam, v));
					  }
					: setParam,
			[hashParam]
		);

		return [param, set];
	};
<commit_msg>fix(use-hash-param): setState only when changed<commit_after>import { useState, useEffect, useMemo } from 'haunted';
import { useMeta } from '@neovici/cosmoz-utils/lib/hooks/use-meta';

const hashUrl = () =>
		new URL(
			location.hash.replace(/^#!?/iu, '').replace('%23', '#'),
			location.origin
		),
	parameterize = (hashParam) =>
		hashParam
			? () =>
					new URLSearchParams(hashUrl().hash.replace('#', '')).get(hashParam)
			: undefined;

export const link = (hashParam, value) => {
		if (!hashParam) {
			return;
		}
		const url = hashUrl(),
			sp = new URLSearchParams(url.hash.replace('#', ''));
		sp.set(hashParam, value);
		return (
			'#!' + Object.assign(url, { hash: sp }).href.replace(location.origin, '')
		);
	},
	useHashParam = (hashParam) => {
		const parameterized = useMemo(() => parameterize(hashParam), [hashParam]),
			[param, setParam] = useState(parameterized),
			meta = useMeta({ param });

		useEffect(() => {
			if (parameterized == null) {
				return;
			}
			const readParam = () => {
				const newParam = parameterized();
				if (meta.param === newParam) {
					return;
				}
				setParam(newParam);
			};
			readParam();
			window.addEventListener('popstate', readParam);
			window.addEventListener('hashchange', readParam);
			return () => {
				window.removeEventListener('popstate', readParam);
				window.removeEventListener('hashchange', readParam);
			};
		}, [parameterized]);

		const set = useMemo(
			() =>
				hashParam
					? (v) => {
							setParam(v);
							history.pushState({}, '', link(hashParam, v));
					  }
					: setParam,
			[hashParam]
		);

		return [param, set];
	};
<|endoftext|>


<commit_before>
/*
 *
 * poloniex-unofficial
 * https://git.io/polonode
 *
 * Yet another unofficial Node.js wrapper for the Poloniex cryptocurrency
 * exchange APIs.
 *
 * Copyright (c) 2016 Tyler Filla
 *
 * This software may be modified and distributed under the terms of the MIT
 * license. See the LICENSE file for details.
 *
 */

/*
 * Order book utility constructor.
 */
function OrderBook() {
    this._wrapperPublic = null;
    this._wrapperPush = null;
}

/*
 *
 * function getWrapperPublic()
 *
 * Get the public wrapper instance.
 *
 */
OrderBook.prototype.getWrapperPublic = function() {
    return this._wrapperPublic;
};

/*
 *
 * function setWrapperPublic(wrapperPublic)
 *
 * Set the public wrapper instance.
 *
 */
OrderBook.prototype.setWrapperPublic = function(wrapperPublic) {
    this._wrapperPublic = wrapperPublic;
};

/*
 *
 * function getWrapperPush()
 *
 * Get the push wrapper instance.
 *
 */
OrderBook.prototype.getWrapperPush = function() {
    return this._wrapperPush;
};

/*
 *
 * function setWrapperPublic(wrapperPublic)
 *
 * Set the push wrapper instance.
 *
 */
OrderBook.prototype.setWrapperPush = function(wrapperPush) {
    this._wrapperPush = wrapperPush;
};

module.exports = OrderBook;
<commit_msg>Added wrapper localization, sanity checks, and a default function<commit_after>
/*
 *
 * poloniex-unofficial
 * https://git.io/polonode
 *
 * Yet another unofficial Node.js wrapper for the Poloniex cryptocurrency
 * exchange APIs.
 *
 * Copyright (c) 2016 Tyler Filla
 *
 * This software may be modified and distributed under the terms of the MIT
 * license. See the LICENSE file for details.
 *
 */

// Localize wrappers
var PushWrapper = module.parent.exports.PushWrapper;
var PublicWrapper = module.parent.exports.PublicWrapper;

// Do not continue without these wrappers
if (!PushWrapper || !PublicWrapper) {
    throw "Failed to localize wrappers (OrderBook.js should not be require()'d externally)";
}

/*
 * Order book utility constructor.
 */
function OrderBook() {
    this._wrapperPublic = null;
    this._wrapperPush = null;
}

/*
 *
 * function getWrapperPush()
 *
 * Get the push wrapper instance.
 *
 */
OrderBook.prototype.getWrapperPush = function() {
    return this._wrapperPush;
};

/*
 *
 * function setWrapperPublic(wrapperPublic)
 *
 * Set the push wrapper instance.
 *
 */
OrderBook.prototype.setWrapperPush = function(wrapperPush) {
    // Sanity check
    if (!(wrapperPush instanceof PushWrapper)) {
        throw new TypeError("wrapperPush is not an instance of PushWrapper");
    }

    this._wrapperPush = wrapperPush;
};

/*
 *
 * function getWrapperPublic()
 *
 * Get the public wrapper instance.
 *
 */
OrderBook.prototype.getWrapperPublic = function() {
    return this._wrapperPublic;
};

/*
 *
 * function setWrapperPublic(wrapperPublic)
 *
 * Set the public wrapper instance.
 *
 */
OrderBook.prototype.setWrapperPublic = function(wrapperPublic) {
    // Sanity check
    if (!(wrapperPublic instanceof PublicWrapper)) {
        throw new TypeError("wrapperPublic is not an instance of PublicWrapper");
    }

    this._wrapperPublic = wrapperPublic;
};

/*
 *
 * function useDefaultWrappers()
 *
 * Create new push and public wrappers and use them.
 *
 */
OrderBook.prototype.useDefaultWrappers = function() {
    this.setWrapperPush(new PushWrapper());
    this.setWrapperPublic(new PublicWrapper());
};

module.exports = OrderBook;
<|endoftext|>


<commit_before>var __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  $ = require('atom-space-pen-views').$,
  DirectoryView = require('./directory-view'),
  ScrollView = require('atom-space-pen-views').ScrollView,
  getObject = require("../helpers").getObject;

var hideLocalTreeError = false;

function hideLocalTree () {
  var treeView = getObject({
    obj:atom.packages.loadedPackages,
    keys:['tree-view', 'mainModule', 'treeView']
  });

  if(treeView && typeof treeView.detach === "function"){ // Fix for Issue 433 ( workaround to stop throwing error)
    try{
      treeView.detach();
    }
    catch(e){
      if(hideLocalTreeError === false){
        hideLocalTreeError = true;
      }
    }
  }

}

function showLocalTree () {
  var treeView = getObject({
    obj:atom.packages.loadedPackages,
    keys:['tree-view', 'mainModule', 'treeView']
  });
  if(treeView && typeof treeView.detach === "function") treeView.attach();
}

module.exports = TreeView = (function (parent) {
  __extends(TreeView, parent);

  var resizeCursor = process.platform === "win32" ? "ew-resize" : "col-resize";

  function TreeView () {
    TreeView.__super__.constructor.apply(this, arguments);

  }

  TreeView.content = function () {
    return this.div({
      'class': 'octophus-view tree-view-resizer tool-panel',
      'data-show-on-right-side': atom.config.get('tree-view.showOnRightSide')
    }, function () {
      this.div({
        'class': 'scroller',
        'outlet': 'scroller'
      }, function () {
        this.ol({
          'class': 'tree-view full-menu list-tree has-collapsable-children focusable-panel',
          'tabindex': -1,
          'outlet': 'list'
        });
      }.bind(this));
      this.div({
        'class': 'resize-handle',
        'outlet': 'horizontalResize',
        "style":"cursor:" + resizeCursor // platform specific cursor
      });
      this.div({
        'class': 'queue tool-panel panel-bottom',
        'tabindex': -1,
        'outlet': 'queue'
      }, function () {
        this.ul({
          'class': 'progress tool-panel panel-top',
          'tabindex': -1,
          'outlet': 'progress'
        });
        this.ul({
          'class': 'list',
          'tabindex': -1,
          'outlet': 'debug'
        });
        return this.div({
          'class': 'resize-handle',
          'outlet': 'verticalResize'
        });
      }.bind(this));
    }.bind(this));
  };

  var elapsedTime = function (ms) {
    var days = Math.floor(ms / 86400000);
    ms %= 86400000;
    var hours = Math.floor(ms / 3600000);
    ms %= 3600000;
    var mins = Math.floor(ms / 60000);
    ms %= 60000;
    var secs = Math.floor(ms / 1000);
    ms %= 1000;

    return ((days ? days + 'd ' : '') +
        (hours ? ((days) && hours < 10 ? '0' : '') + hours + 'h ' : '') +
        (mins ? ((days || hours) && mins < 10 ? '0' : '') + mins + 'm ' : '') +
        (secs ? ((days || hours || mins) && secs < 10 ? '0' : '') + secs + 's ' : '')).replace(/^[dhms]\s+/, '').replace(/[dhms]\s+[dhms]/g, '').replace(/^\s+/, '').replace(/\s+$/, '') || '0s';
  };

  TreeView.prototype.setRoot = function(root) {
    atom.project.octophusdir.ghDir = root.ghDir;
    atom.project.octophusdir.name = root.name;
    atom.project.octophusdir.folders = root.folders;
    atom.project.octophusdir.files = root.files;
  }

  TreeView.prototype.setRootName = function(name) {
    atom.project.octophusdir.name = name;
    this.root.repaint();
  }

  TreeView.prototype.initialize = function (state) {
    TreeView.__super__.initialize.apply(this, arguments);

    var self = this;

    //self.addClass(atom.config.get('tree-view.showOnRightSide') ? 'panel-right' : 'panel-left');
    self.showOnline();

    self.root = new DirectoryView(atom.project.octophusdir);
    self.root.expand();
    self.list.append(self.root);

    //self.attach();

    // Events
    atom.config.onDidChange('tree-view.showOnRightSide', function () {
      if (self.isVisible()) {
        setTimeout(function () {
          self.detach();
          self.attach();
        }, 1);
      }
    });

    self.horizontalResize.on('dblclick', function (e) { self.resizeToFitContent(e); });
    self.horizontalResize.on('mousedown', function (e) { self.resizeHorizontalStarted(e); });
    self.verticalResize.on('mousedown', function (e) { self.resizeVerticalStarted(e); });
    self.list.on('keydown', function (e) { self.remoteKeyboardNavigation(e); });

    self.showOnline();
  };

  TreeView.prototype.attach = function () {
    if (atom.config.get('tree-view.showOnRightSide')) {
      this.panel = atom.workspace.addRightPanel({item: this});
    } else {
      this.panel = atom.workspace.addLeftPanel({item: this});
    }

    hideLocalTree();
  };

  TreeView.prototype.detach = function () {
    TreeView.__super__.detach.apply(this, arguments);

    if (this.panel) {
      this.panel.destroy();
      this.panel = null;
    }

    showLocalTree();
  };

  TreeView.prototype.toggle = function () {
    if (this.isVisible()) {
      this.detach();
    } else {
      this.attach();
    }
  };

  TreeView.prototype.showOnline = function () {
    this.list.show();
    this.queue.show();
  };

  TreeView.prototype.resolve = function (path) {
    var view = $('.octophus-view [data-path="'+ path +'"]').map(function () {
        var v = $(this).view();
        return v ? v : null;
      }).get(0);

    return view;
  };

  TreeView.prototype.getSelected = function () {
    console.log('runned.');
    var views = $('.octophus-view .selected').map(function () {
        var v = $(this).view();
        return v ? v : null;
      }).get();

    return views;
  };

  TreeView.prototype.resizeVerticalStarted = function (e) {
    e.preventDefault();

    this.resizeHeightStart = this.queue.height();
    this.resizeMouseStart = e.pageY;
    $(document).on('mousemove', this.resizeVerticalView.bind(this));
    $(document).on('mouseup', this.resizeVerticalStopped);
  };

  TreeView.prototype.resizeVerticalStopped = function () {
    delete this.resizeHeightStart;
    delete this.resizeMouseStart;
    $(document).off('mousemove', this.resizeVerticalView);
    $(document).off('mouseup', this.resizeVerticalStopped);
  };

  TreeView.prototype.resizeVerticalView = function (e) {
    if (e.which !== 1)
      return this.resizeVerticalStopped();

    var delta = e.pageY - this.resizeMouseStart,
      height = Math.max(26, this.resizeHeightStart - delta);

    this.queue.height(height);
    this.scroller.css('bottom', height + 'px');
  };

  TreeView.prototype.resizeHorizontalStarted = function (e) {
    e.preventDefault();

    this.resizeWidthStart = this.width();
    this.resizeMouseStart = e.pageX;
    $(document).on('mousemove', this.resizeHorizontalView.bind(this));
    $(document).on('mouseup', this.resizeHorizontalStopped);
  };

  TreeView.prototype.resizeHorizontalStopped = function () {
    delete this.resizeWidthStart;
    delete this.resizeMouseStart;
    $(document).off('mousemove', this.resizeHorizontalView);
    $(document).off('mouseup', this.resizeHorizontalStopped);
  };

  TreeView.prototype.resizeHorizontalView = function (e) {
    if (e.which !== 1)
      return this.resizeHorizontalStopped();

    var delta = e.pageX - this.resizeMouseStart,
      width = Math.max(50, this.resizeWidthStart + delta);

    this.width(width);
  };

  TreeView.prototype.resizeToFitContent = function (e) {
    e.preventDefault();

    this.width(1);
    this.width(this.list.outerWidth());
  };

  TreeView.prototype.remoteKeyboardNavigation = function (e) {
    var arrows = {left: 37, up: 38, right: 39, down: 40 },
      keyCode = e.keyCode || e.which;

    switch (keyCode) {
      case arrows.up:
        this.remoteKeyboardNavigationUp();
        break;
      case arrows.down:
        this.remoteKeyboardNavigationDown();
        break;
      case arrows.left:
        this.remoteKeyboardNavigationLeft();
        break;
      case arrows.right:
        this.remoteKeyboardNavigationRight();
        break;
      default:
        return;
    }

    e.preventDefault();
    e.stopPropagation();
    this.remoteKeyboardNavigationMovePage();
  };

  TreeView.prototype.remoteKeyboardNavigationUp = function () {
    var current = this.list.find('.selected'),
      next = current.prev('.entry:visible');
    if (next.length) {
      while (next.is('.expanded') && next.find('.entries .entry:visible').length) {
        next = next.find('.entries .entry:visible');
      }
    } else {
      next = current.closest('.entries').closest('.entry:visible');
    }
    if (next.length) {
      current.removeClass('selected');
      next.last().addClass('selected');
    }
  };

  TreeView.prototype.remoteKeyboardNavigationDown = function () {
    var current = this.list.find('.selected'),
      next = current.find('.entries .entry:visible');
    if (!next.length) {
      tmp = current;
      do {
        next = tmp.next('.entry:visible');
        if (!next.length) {
          tmp = tmp.closest('.entries').closest('.entry:visible');
        }
      } while (!next.length && !tmp.is('.project-root'));
    }
    if (next.length) {
      current.removeClass('selected');
      next.first().addClass('selected');
    }
  };

  TreeView.prototype.remoteKeyboardNavigationLeft = function () {
    var current = this.list.find('.selected');
    if (!current.is('.directory')) {
      next = current.closest('.directory');
      next.view().collapse();
      current.removeClass('selected');
      next.first().addClass('selected');
    } else {
      current.view().collapse();
    }
  };

  TreeView.prototype.remoteKeyboardNavigationRight = function () {
    var current = this.list.find('.selected');
    if (current.is('.directory')) {
      var view = current.view();
      view.open();
      view.expand();
    }
  };

  TreeView.prototype.remoteKeyboardNavigationMovePage = function () {
    var current = this.list.find('.selected');
    if (current.length) {
      var scrollerTop = this.scroller.scrollTop(),
        selectedTop = current.position().top;
      if (selectedTop < scrollerTop - 10) {
        this.scroller.pageUp();
      } else if (selectedTop > scrollerTop + this.scroller.height() - 10) {
        this.scroller.pageDown();
      }
    }
  };

  return TreeView;

})(ScrollView);
<commit_msg>button<commit_after>var __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  $ = require('atom-space-pen-views').$,
  DirectoryView = require('./directory-view'),
  ScrollView = require('atom-space-pen-views').ScrollView,
  getObject = require("../helpers").getObject;

var hideLocalTreeError = false;

function hideLocalTree () {
  var treeView = getObject({
    obj:atom.packages.loadedPackages,
    keys:['tree-view', 'mainModule', 'treeView']
  });

  if(treeView && typeof treeView.detach === "function"){ // Fix for Issue 433 ( workaround to stop throwing error)
    try{
      treeView.detach();
    }
    catch(e){
      if(hideLocalTreeError === false){
        hideLocalTreeError = true;
      }
    }
  }

}

function showLocalTree () {
  var treeView = getObject({
    obj:atom.packages.loadedPackages,
    keys:['tree-view', 'mainModule', 'treeView']
  });
  if(treeView && typeof treeView.detach === "function") treeView.attach();
}

module.exports = TreeView = (function (parent) {
  __extends(TreeView, parent);

  var resizeCursor = process.platform === "win32" ? "ew-resize" : "col-resize";

  function TreeView () {
    TreeView.__super__.constructor.apply(this, arguments);

  }

  TreeView.content = function () {
    return this.div({
      'class': 'octophus-view tree-view-resizer tool-panel',
      'data-show-on-right-side': atom.config.get('tree-view.showOnRightSide')
    }, function () {
      this.div({
        'class': 'scroller',
        'outlet': 'scroller'
      }, function () {
        this.ol({
          'class': 'tree-view full-menu list-tree has-collapsable-children focusable-panel',
          'tabindex': -1,
          'outlet': 'list'
        });
      }.bind(this));
      this.div({
        'class': 'resize-handle',
        'outlet': 'horizontalResize',
        "style":"cursor:" + resizeCursor // platform specific cursor
      });
      this.div({
        'class': 'queue tool-panel panel-bottom',
        'tabindex': -1,
        'outlet': 'queue'
      }, function () {
        this.ul({
          'class': 'progress tool-panel panel-top',
          'tabindex': -1,
          'outlet': 'progress'
        });
        this.ul({
          'class': 'list',
          'tabindex': -1,
          'outlet': 'debug'
        });
        this.button('Commit', {
          'class': 'btn btn-default icon',
          'style': 'width: 100%; font-size: 9pt;',
          'on-click': 'atom.project.octophuscommit();'
        });
        return this.div({
          'class': 'resize-handle',
          'outlet': 'verticalResize'
        });
      }.bind(this));
    }.bind(this));
  };

  var elapsedTime = function (ms) {
    var days = Math.floor(ms / 86400000);
    ms %= 86400000;
    var hours = Math.floor(ms / 3600000);
    ms %= 3600000;
    var mins = Math.floor(ms / 60000);
    ms %= 60000;
    var secs = Math.floor(ms / 1000);
    ms %= 1000;

    return ((days ? days + 'd ' : '') +
        (hours ? ((days) && hours < 10 ? '0' : '') + hours + 'h ' : '') +
        (mins ? ((days || hours) && mins < 10 ? '0' : '') + mins + 'm ' : '') +
        (secs ? ((days || hours || mins) && secs < 10 ? '0' : '') + secs + 's ' : '')).replace(/^[dhms]\s+/, '').replace(/[dhms]\s+[dhms]/g, '').replace(/^\s+/, '').replace(/\s+$/, '') || '0s';
  };

  TreeView.prototype.setRoot = function(root) {
    atom.project.octophusdir.ghDir = root.ghDir;
    atom.project.octophusdir.name = root.name;
    atom.project.octophusdir.folders = root.folders;
    atom.project.octophusdir.files = root.files;
  }

  TreeView.prototype.setRootName = function(name) {
    atom.project.octophusdir.name = name;
    this.root.repaint();
  }

  TreeView.prototype.initialize = function (state) {
    TreeView.__super__.initialize.apply(this, arguments);

    var self = this;

    //self.addClass(atom.config.get('tree-view.showOnRightSide') ? 'panel-right' : 'panel-left');
    self.showOnline();

    self.root = new DirectoryView(atom.project.octophusdir);
    self.root.expand();
    self.list.append(self.root);

    //self.attach();

    // Events
    atom.config.onDidChange('tree-view.showOnRightSide', function () {
      if (self.isVisible()) {
        setTimeout(function () {
          self.detach();
          self.attach();
        }, 1);
      }
    });

    self.horizontalResize.on('dblclick', function (e) { self.resizeToFitContent(e); });
    self.horizontalResize.on('mousedown', function (e) { self.resizeHorizontalStarted(e); });
    self.verticalResize.on('mousedown', function (e) { self.resizeVerticalStarted(e); });
    self.list.on('keydown', function (e) { self.remoteKeyboardNavigation(e); });

    self.showOnline();
  };

  TreeView.prototype.attach = function () {
    if (atom.config.get('tree-view.showOnRightSide')) {
      this.panel = atom.workspace.addRightPanel({item: this});
    } else {
      this.panel = atom.workspace.addLeftPanel({item: this});
    }

    hideLocalTree();
  };

  TreeView.prototype.detach = function () {
    TreeView.__super__.detach.apply(this, arguments);

    if (this.panel) {
      this.panel.destroy();
      this.panel = null;
    }

    showLocalTree();
  };

  TreeView.prototype.toggle = function () {
    if (this.isVisible()) {
      this.detach();
    } else {
      this.attach();
    }
  };

  TreeView.prototype.showOnline = function () {
    this.list.show();
    this.queue.show();
  };

  TreeView.prototype.resolve = function (path) {
    var view = $('.octophus-view [data-path="'+ path +'"]').map(function () {
        var v = $(this).view();
        return v ? v : null;
      }).get(0);

    return view;
  };

  TreeView.prototype.getSelected = function () {
    console.log('runned.');
    var views = $('.octophus-view .selected').map(function () {
        var v = $(this).view();
        return v ? v : null;
      }).get();

    return views;
  };

  TreeView.prototype.resizeVerticalStarted = function (e) {
    e.preventDefault();

    this.resizeHeightStart = this.queue.height();
    this.resizeMouseStart = e.pageY;
    $(document).on('mousemove', this.resizeVerticalView.bind(this));
    $(document).on('mouseup', this.resizeVerticalStopped);
  };

  TreeView.prototype.resizeVerticalStopped = function () {
    delete this.resizeHeightStart;
    delete this.resizeMouseStart;
    $(document).off('mousemove', this.resizeVerticalView);
    $(document).off('mouseup', this.resizeVerticalStopped);
  };

  TreeView.prototype.resizeVerticalView = function (e) {
    if (e.which !== 1)
      return this.resizeVerticalStopped();

    var delta = e.pageY - this.resizeMouseStart,
      height = Math.max(26, this.resizeHeightStart - delta);

    this.queue.height(height);
    this.scroller.css('bottom', height + 'px');
  };

  TreeView.prototype.resizeHorizontalStarted = function (e) {
    e.preventDefault();

    this.resizeWidthStart = this.width();
    this.resizeMouseStart = e.pageX;
    $(document).on('mousemove', this.resizeHorizontalView.bind(this));
    $(document).on('mouseup', this.resizeHorizontalStopped);
  };

  TreeView.prototype.resizeHorizontalStopped = function () {
    delete this.resizeWidthStart;
    delete this.resizeMouseStart;
    $(document).off('mousemove', this.resizeHorizontalView);
    $(document).off('mouseup', this.resizeHorizontalStopped);
  };

  TreeView.prototype.resizeHorizontalView = function (e) {
    if (e.which !== 1)
      return this.resizeHorizontalStopped();

    var delta = e.pageX - this.resizeMouseStart,
      width = Math.max(50, this.resizeWidthStart + delta);

    this.width(width);
  };

  TreeView.prototype.resizeToFitContent = function (e) {
    e.preventDefault();

    this.width(1);
    this.width(this.list.outerWidth());
  };

  TreeView.prototype.remoteKeyboardNavigation = function (e) {
    var arrows = {left: 37, up: 38, right: 39, down: 40 },
      keyCode = e.keyCode || e.which;

    switch (keyCode) {
      case arrows.up:
        this.remoteKeyboardNavigationUp();
        break;
      case arrows.down:
        this.remoteKeyboardNavigationDown();
        break;
      case arrows.left:
        this.remoteKeyboardNavigationLeft();
        break;
      case arrows.right:
        this.remoteKeyboardNavigationRight();
        break;
      default:
        return;
    }

    e.preventDefault();
    e.stopPropagation();
    this.remoteKeyboardNavigationMovePage();
  };

  TreeView.prototype.remoteKeyboardNavigationUp = function () {
    var current = this.list.find('.selected'),
      next = current.prev('.entry:visible');
    if (next.length) {
      while (next.is('.expanded') && next.find('.entries .entry:visible').length) {
        next = next.find('.entries .entry:visible');
      }
    } else {
      next = current.closest('.entries').closest('.entry:visible');
    }
    if (next.length) {
      current.removeClass('selected');
      next.last().addClass('selected');
    }
  };

  TreeView.prototype.remoteKeyboardNavigationDown = function () {
    var current = this.list.find('.selected'),
      next = current.find('.entries .entry:visible');
    if (!next.length) {
      tmp = current;
      do {
        next = tmp.next('.entry:visible');
        if (!next.length) {
          tmp = tmp.closest('.entries').closest('.entry:visible');
        }
      } while (!next.length && !tmp.is('.project-root'));
    }
    if (next.length) {
      current.removeClass('selected');
      next.first().addClass('selected');
    }
  };

  TreeView.prototype.remoteKeyboardNavigationLeft = function () {
    var current = this.list.find('.selected');
    if (!current.is('.directory')) {
      next = current.closest('.directory');
      next.view().collapse();
      current.removeClass('selected');
      next.first().addClass('selected');
    } else {
      current.view().collapse();
    }
  };

  TreeView.prototype.remoteKeyboardNavigationRight = function () {
    var current = this.list.find('.selected');
    if (current.is('.directory')) {
      var view = current.view();
      view.open();
      view.expand();
    }
  };

  TreeView.prototype.remoteKeyboardNavigationMovePage = function () {
    var current = this.list.find('.selected');
    if (current.length) {
      var scrollerTop = this.scroller.scrollTop(),
        selectedTop = current.position().top;
      if (selectedTop < scrollerTop - 10) {
        this.scroller.pageUp();
      } else if (selectedTop > scrollerTop + this.scroller.height() - 10) {
        this.scroller.pageDown();
      }
    }
  };

  return TreeView;

})(ScrollView);
<|endoftext|>


<commit_before>'use strict';

var CachingWriter = require('broccoli-caching-writer');
var path = require('path');
var fs = require('fs');
var _ = require('lodash');
var mkdirp = require('mkdirp');

function filtersFor(assets, filters) {
  return filters.map(function(filter) {
    return {
      name: filter.name,
      key: filter.key,
      items: _
        .chain(assets)
        .map(filter.key)
        .without(undefined)
        .countBy()
        .toPairs()
        .map(function(pair) {
          return { name: pair[0], count: pair[1] };
        })
        .sortBy('name')
        .value()
    };
  });
}

function ViewerBuilder(inputNode, options) {
  if (!options || !options.outputFile) {
    throw new Error('the outputFile option is required');
  }

  CachingWriter.call(this, [inputNode], {
    name: 'ViewerBuilder',
    annotation: options.annotation,
  });

  this.options = options;
}

ViewerBuilder.prototype = Object.create(CachingWriter.prototype);
ViewerBuilder.prototype.constructor = ViewerBuilder;

ViewerBuilder.prototype.build = function() {
  var viewerContent = JSON.stringify(this.getViewerModel());
  var outputFilePath = path.join(this.outputPath, this.options.outputFile);
  mkdirp.sync(path.dirname(outputFilePath));
  fs.writeFileSync(outputFilePath, viewerContent);
};

ViewerBuilder.prototype.getViewerModel = function() {
  var viewerAssets = this.listFiles().reduce(function(assets, filePath) {
    return assets.concat(JSON.parse(fs.readFileSync(filePath, 'UTF-8')));
  }, []);

  return {
    sortBy: [
      { name: 'File name', key: 'fileName' },
      { name: 'Base size', key: 'baseSize' }
    ],

    arrangeBy: [
      { name: 'Directory', key: 'fileDir' },
      { name: 'Base size', key: 'baseSize' }
    ],

    searchKeys: ['fileName', 'fileDir'],

    filters: filtersFor(viewerAssets, [
      { name: 'Directory', key: 'fileDir' },
      { name: 'Base size', key: 'baseSize' }
    ]),

    details: [
      { name: 'File name', key: 'fileName' },
      { name: 'Directory', key: 'fileDir' },
      { name: 'Base size', key: 'baseSize' }
    ],

    assets: viewerAssets
  };
};

module.exports = ViewerBuilder;
<commit_msg>Improve ViewerBuilder code<commit_after>'use strict';

var CachingWriter = require('broccoli-caching-writer');
var path = require('path');
var fs = require('fs');
var _ = require('lodash');
var mkdirp = require('mkdirp');

function filtersFor(assets, filters) {
  return filters.map(function(filter) {
    return {
      name: filter.name,
      key: filter.key,
      items: _
        .chain(assets)
        .map(filter.key)
        .without(undefined)
        .countBy()
        .toPairs()
        .map(function(pair) {
          return { name: pair[0], count: pair[1] };
        })
        .sortBy('name')
        .value()
    };
  });
}

function ViewerBuilder(inputNode, options) {
  if (!options || !options.outputFile) {
    throw new Error('the outputFile option is required');
  }

  CachingWriter.call(this, [inputNode], {
    name: 'ViewerBuilder',
    annotation: options.annotation,
  });

  this.options = options;
}

ViewerBuilder.prototype = Object.create(CachingWriter.prototype);
ViewerBuilder.prototype.constructor = ViewerBuilder;

ViewerBuilder.prototype.build = function() {
  var viewerContent = JSON.stringify(this.getViewerModel());
  var outputFilePath = path.join(this.outputPath, this.options.outputFile);
  mkdirp.sync(path.dirname(outputFilePath));
  fs.writeFileSync(outputFilePath, viewerContent);
};

ViewerBuilder.prototype.getViewerModel = function() {
  var assets = this.listFiles().reduce(function(assets, filePath) {
    return assets.concat(JSON.parse(fs.readFileSync(filePath, 'UTF-8')));
  }, []);

  var searchKeys = ['fileName', 'fileDir'];

  var sortBy = [
    { name: 'File name', key: 'fileName' },
    { name: 'Base size', key: 'baseSize' }
  ];

  var arrangeBy = [
    { name: 'Directory', key: 'fileDir' },
    { name: 'Base size', key: 'baseSize' }
  ];

  var filterBy = [
    { name: 'Directory', key: 'fileDir' },
    { name: 'Base size', key: 'baseSize' }
  ];

  var details = [
    { name: 'File name', key: 'fileName' },
    { name: 'Directory', key: 'fileDir' },
    { name: 'Base size', key: 'baseSize' }
  ];

  return {
    assets: assets,
    searchKeys: searchKeys,
    sortBy: sortBy,
    arrangeBy: arrangeBy,
    filters: filtersFor(assets, filterBy),
    details: details
  };
};

module.exports = ViewerBuilder;
<|endoftext|>


<commit_before>'use strict'

const Router = require('express').Router
const passport = require('passport')

const config = require('../../config')
const logger = require('../../logger')
const models = require('../../models')

const authRouter = module.exports = Router()

// serialize and deserialize
passport.serializeUser(function (user, done) {
  logger.info('serializeUser: ' + user.id)
  return done(null, user.id)
})

passport.deserializeUser(function (id, done) {
  models.User.findOne({
    where: {
      id: id
    }
  }).then(function (user) {
    logger.info('deserializeUser: ' + user.id)
    return done(null, user)
  }).catch(function (err) {
    logger.error(err)
    return done(err, null)
  })
})

if (config.isFacebookEnable) authRouter.use(require('./facebook'))
if (config.isTwitterEnable) authRouter.use(require('./twitter'))
if (config.isGitHubEnable) authRouter.use(require('./github'))
if (config.isGitLabEnable) authRouter.use(require('./gitlab'))
if (config.isMattermostEnable) authRouter.use(require('./mattermost'))
if (config.isDropboxEnable) authRouter.use(require('./dropbox'))
if (config.isGoogleEnable) authRouter.use(require('./google'))
if (config.isLDAPEnable) authRouter.use(require('./ldap'))
if (config.isSAMLEnable) authRouter.use(require('./saml'))
if (config.isEmailEnable) authRouter.use(require('./email'))

// logout
authRouter.get('/logout', function (req, res) {
  if (config.debug && req.isAuthenticated()) {
    logger.debug('user logout: ' + req.user.id)
  }
  req.logout()
  res.redirect(config.serverurl + '/')
})
<commit_msg>Fix uncaught exception for non-existent user<commit_after>'use strict'

const Router = require('express').Router
const passport = require('passport')

const config = require('../../config')
const logger = require('../../logger')
const models = require('../../models')

const authRouter = module.exports = Router()

// serialize and deserialize
passport.serializeUser(function (user, done) {
  logger.info('serializeUser: ' + user.id)
  return done(null, user.id)
})

passport.deserializeUser(function (id, done) {
  models.User.findOne({
    where: {
      id: id
    }
  }).then(function (user) {
    // Don't die on non-existent user
    if (user == null) {
      return done(null, false, { message: 'Invalid UserID' })
    }

    logger.info('deserializeUser: ' + user.id)
    return done(null, user)
  }).catch(function (err) {
    logger.error(err)
    return done(err, null)
  })
})

if (config.isFacebookEnable) authRouter.use(require('./facebook'))
if (config.isTwitterEnable) authRouter.use(require('./twitter'))
if (config.isGitHubEnable) authRouter.use(require('./github'))
if (config.isGitLabEnable) authRouter.use(require('./gitlab'))
if (config.isMattermostEnable) authRouter.use(require('./mattermost'))
if (config.isDropboxEnable) authRouter.use(require('./dropbox'))
if (config.isGoogleEnable) authRouter.use(require('./google'))
if (config.isLDAPEnable) authRouter.use(require('./ldap'))
if (config.isSAMLEnable) authRouter.use(require('./saml'))
if (config.isEmailEnable) authRouter.use(require('./email'))

// logout
authRouter.get('/logout', function (req, res) {
  if (config.debug && req.isAuthenticated()) {
    logger.debug('user logout: ' + req.user.id)
  }
  req.logout()
  res.redirect(config.serverurl + '/')
})
<|endoftext|>