<commit_before>var SteamCommunity = require('steamcommunity');

module.exports = TradeOfferManager;

TradeOfferManager.SteamID = require('steamid');
TradeOfferManager.ETradeOfferState = require('../resources/ETradeOfferState.js');
TradeOfferManager.EOfferFilter = require('../resources/EOfferFilter.js');
TradeOfferManager.EResult = require('../resources/EResult.js');

TradeOfferManager.getStateName = function(state) {
	for(var i in TradeOfferManager.ETradeOfferState) {
		if(TradeOfferManager.ETradeOfferState[i] == state) {
			return i;
		}
	}

	return state;
};

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

function TradeOfferManager(options) {
	options = options || {};

	this._steam = options.steam;
	this._domain = options.domain || 'localhost';
	this._language = options.language;
	this._pollInterval = options.pollInterval || 30000;
	this._cancelTime = options.cancelTime;

	this._community = new SteamCommunity();
	this._request = this._community.request;
	this._assetCache = {};
	this._pollTimer = null;
	this._lastPoll = 0;

	this.pollData = {};
	this.apiKey = null;

	if(this._language) {
		var lang = require('languages').getLanguageInfo(this._language);
		if(!lang.name) {
			this._language = null;
			this._languageName = null;
		} else {
			this._languageName = lang.name.toLowerCase();
		}
	}

	if(this._steam) {
		this._steam.on('tradeOffers', function(count) {
			this.doPoll();
		}.bind(this));

		// This is emitted by https://www.npmjs.com/package/steam-user when new items are announced
		this._steam.on('newItems', function(count) {
			this.doPoll();
		}.bind(this));
	}
}

TradeOfferManager.prototype.setCookies = function(cookies, callback) {
	if(this._languageName) {
		cookies = cookies.concat(['Steam_Language=' + this._languageName]);
	}

	this._community.setCookies(cookies);
	this._checkApiKey(function(err) {
		if(!err) {
			if(!this._pollTimer && this._pollInterval >= 1000) {
				this.doPoll();
			}
		}

		callback(err);
	}.bind(this));
};

TradeOfferManager.prototype.parentalUnlock = function(pin, callback) {
	this._community.parentalUnlock(pin, function(err) {
		if(err && callback) {
			callback(err);
		}
	});
};

TradeOfferManager.prototype._checkApiKey = function(callback) {
	if(this.apiKey) {
		if(callback) {
			callback();
		}

		return;
	}

	this._community.getWebApiKey(this._domain, function(err, key) {
		if(err) {
			callback(err);
			return;
		}

		this.apiKey = key;
		callback();
	}.bind(this));
};

TradeOfferManager.prototype.loadInventory = function(appid, contextid, tradableOnly, callback, data, start) {
	this._request('https://steamcommunity.com/my/inventory/json/' + appid + '/' + contextid + '/', {
		"qs": {
			"start": start,
			"l": this._languageName,
			"trading": tradableOnly ? 1 : undefined
		},
		"json": true
	}, function(err, response, body) {
		if(err || response.statusCode != 200) {
			callback(err || new Error("HTTP error " + response.statusCode));
			return;
		}

		if(!body || !body.success || !body.rgInventory || !body.rgDescriptions || !body.rgCurrency) {
			callback(new Error("Malformed response"));
			return;
		}

		this._digestDescriptions(body.rgDescriptions);

		data = (data || []).concat(this._mapItemsToDescriptions(appid, contextid, body.rgInventory)).concat(this._mapItemsToDescriptions(appid, contextid, body.rgCurrency));
		if(body.more) {
			this.loadInventory(appid, contextid, tradableOnly, callback, data, body.more_start);
		} else {
			callback(null, data);
		}
	}.bind(this));
};

TradeOfferManager.prototype.getOfferToken = function(callback) {
	this._request("https://steamcommunity.com/my/tradeoffers/privacy", function(err, response, body) {
		if(err || response.statusCode != 200) {
			callback(err || new Error("HTTP error " + response.statusCode));
			return;
		}

		var match = body.match(/https?:\/\/(www.)?steamcommunity.com\/tradeoffer\/new\/?\?partner=\d+(&|&)token=([a-zA-Z0-9_]+)/);
		if(match) {
			callback(null, match[3]);
		} else {
			callback(new Error("Malformed response"));
		}
	});
};

function makeAnError(error, callback) {
	if(callback) {
		callback(error);
	}
}

require('./webapi.js');
require('./assets.js');
require('./polling.js');
require('./classes/TradeOffer.js');
<commit_msg>Fixed trade offer token regex not including dash<commit_after>var SteamCommunity = require('steamcommunity');

module.exports = TradeOfferManager;

TradeOfferManager.SteamID = require('steamid');
TradeOfferManager.ETradeOfferState = require('../resources/ETradeOfferState.js');
TradeOfferManager.EOfferFilter = require('../resources/EOfferFilter.js');
TradeOfferManager.EResult = require('../resources/EResult.js');

TradeOfferManager.getStateName = function(state) {
	for(var i in TradeOfferManager.ETradeOfferState) {
		if(TradeOfferManager.ETradeOfferState[i] == state) {
			return i;
		}
	}

	return state;
};

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

function TradeOfferManager(options) {
	options = options || {};

	this._steam = options.steam;
	this._domain = options.domain || 'localhost';
	this._language = options.language;
	this._pollInterval = options.pollInterval || 30000;
	this._cancelTime = options.cancelTime;

	this._community = new SteamCommunity();
	this._request = this._community.request;
	this._assetCache = {};
	this._pollTimer = null;
	this._lastPoll = 0;

	this.pollData = {};
	this.apiKey = null;

	if(this._language) {
		var lang = require('languages').getLanguageInfo(this._language);
		if(!lang.name) {
			this._language = null;
			this._languageName = null;
		} else {
			this._languageName = lang.name.toLowerCase();
		}
	}

	if(this._steam) {
		this._steam.on('tradeOffers', function(count) {
			this.doPoll();
		}.bind(this));

		// This is emitted by https://www.npmjs.com/package/steam-user when new items are announced
		this._steam.on('newItems', function(count) {
			this.doPoll();
		}.bind(this));
	}
}

TradeOfferManager.prototype.setCookies = function(cookies, callback) {
	if(this._languageName) {
		cookies = cookies.concat(['Steam_Language=' + this._languageName]);
	}

	this._community.setCookies(cookies);
	this._checkApiKey(function(err) {
		if(!err) {
			if(!this._pollTimer && this._pollInterval >= 1000) {
				this.doPoll();
			}
		}

		callback(err);
	}.bind(this));
};

TradeOfferManager.prototype.parentalUnlock = function(pin, callback) {
	this._community.parentalUnlock(pin, function(err) {
		if(err && callback) {
			callback(err);
		}
	});
};

TradeOfferManager.prototype._checkApiKey = function(callback) {
	if(this.apiKey) {
		if(callback) {
			callback();
		}

		return;
	}

	this._community.getWebApiKey(this._domain, function(err, key) {
		if(err) {
			callback(err);
			return;
		}

		this.apiKey = key;
		callback();
	}.bind(this));
};

TradeOfferManager.prototype.loadInventory = function(appid, contextid, tradableOnly, callback, data, start) {
	this._request('https://steamcommunity.com/my/inventory/json/' + appid + '/' + contextid + '/', {
		"qs": {
			"start": start,
			"l": this._languageName,
			"trading": tradableOnly ? 1 : undefined
		},
		"json": true
	}, function(err, response, body) {
		if(err || response.statusCode != 200) {
			callback(err || new Error("HTTP error " + response.statusCode));
			return;
		}

		if(!body || !body.success || !body.rgInventory || !body.rgDescriptions || !body.rgCurrency) {
			callback(new Error("Malformed response"));
			return;
		}

		this._digestDescriptions(body.rgDescriptions);

		data = (data || []).concat(this._mapItemsToDescriptions(appid, contextid, body.rgInventory)).concat(this._mapItemsToDescriptions(appid, contextid, body.rgCurrency));
		if(body.more) {
			this.loadInventory(appid, contextid, tradableOnly, callback, data, body.more_start);
		} else {
			callback(null, data);
		}
	}.bind(this));
};

TradeOfferManager.prototype.getOfferToken = function(callback) {
	this._request("https://steamcommunity.com/my/tradeoffers/privacy", function(err, response, body) {
		if(err || response.statusCode != 200) {
			callback(err || new Error("HTTP error " + response.statusCode));
			return;
		}

		var match = body.match(/https?:\/\/(www.)?steamcommunity.com\/tradeoffer\/new\/?\?partner=\d+(&|&)token=([a-zA-Z0-9-_]+)/);
		if(match) {
			callback(null, match[3]);
		} else {
			callback(new Error("Malformed response"));
		}
	});
};

function makeAnError(error, callback) {
	if(callback) {
		callback(error);
	}
}

require('./webapi.js');
require('./assets.js');
require('./polling.js');
require('./classes/TradeOffer.js');
<|endoftext|>


<commit_before>'use strict';

const fs      = require('fs');
const Clapp   = require('./modules/clapp-discord');
const cfg     = require('../config.js');
const pkg     = require('../package.json');
const Discord = require('discord.js');
const bot     = new Discord.Client();
const tumblrLib  = require('tumblr');
const foodsites  = require('../foodtumblrs.js').sites;
const shibesites = require('../shibetumblrs.js').sites;
const birbsites = require('../birbtumblrs.js').sites;
const duccsites = require('../ducctumblrs.js').sites;

// Heroku workaround
const http = require('http');

const server = http.createServer( (req, res) => {
	res.writeHead(200, {'Content-Type': 'text/plain'});
})
server.listen( process.env.PORT );

var app = new Clapp.App({
  name: cfg.name,
  desc: pkg.description,
  prefix: cfg.prefix,
  version: pkg.version,
  onReply: (msg, context) => {
    // Fired when input is needed to be shown to the user.

    context.msg.reply('\n' + msg).then(bot_response => {
      if (cfg.deleteAfterReply.enabled) {
        context.msg.delete(cfg.deleteAfterReply.time)
          .then(msg => console.log(`Deleted message from ${msg.author}`))
          .catch(console.log);
        bot_response.delete(cfg.deleteAfterReply.time)
          .then(msg => console.log(`Deleted message from ${msg.author}`))
          .catch(console.log);
      }
    });
  }
});

// Load every command in the commands folder
fs.readdirSync('./lib/commands/').forEach(file => {
  app.addCommand(require("./commands/" + file));
});

bot.on('message', msg => {
  // Fired when someone sends a message
  if (!msg.content.startsWith('!')) return;
  if (msg.author.bot) return;

  if (msg.content === '!food') {
		getRandomPhoto( msg, foodsites );
  }

  else if (msg.content === '!shibe') {
  		getRandomPhoto( msg, shibesites );
  }

  else if (msg.content === '!birb') {
  		getRandomPhoto( msg, birbsites );
  }

  else if (msg.content === '!ducc') {
  		getRandomPhoto( msg, duccsites );
  }

  if (app.isCliSentence(msg.content)) {
    app.parseInput(msg.content, {
      msg: msg
      // Keep adding properties to the context as you need them
    });
  }

});

bot.login(cfg.token).then(() => {
  console.log('Discord bot running!');
});

function getRandomPhoto( msg, sites, callback ) {

	var site = sites[Math.floor(Math.random()*sites.length)];
	var blog = new tumblrLib.Blog(site, cfg.tumblr_OAuth );

	console.log( '------\nSite: ' + site + '\n' );
	var url = getURL( blog, function( url ) {
		msg.reply( url );
	});
};

function getURL( blog, offset, callback ) {

	var offset = 0;
	blog.photo( {type: 'photo', limit: '1'}, function( error, response ) {

		if( !response ) {
			return callback( "Try again later." );
		}

		console.log( 'Offset: ' + offset + '\n');

		offset = Math.floor( Math.random() * response.total_posts );

		console.log( 'Offset: ' + offset + '\n');

		blog.photo( {type: 'photo', limit: '1', offset: offset}, function(error, response) {

			// pick a post
			var posts = response.posts;
			var url = posts[0].photos[0].original_size.url;
			console.log( 'url: ' + url );
			return callback( url );
		});
	});

};<commit_msg>Fix the thing<commit_after>'use strict';

const fs      = require('fs');
const Clapp   = require('./modules/clapp-discord');
const cfg     = require('../config.js');
const pkg     = require('../package.json');
const Discord = require('discord.js');
const bot     = new Discord.Client();
const tumblrLib  = require('tumblr');
const foodsites  = require('../foodtumblrs.js').sites;
const shibesites = require('../shibetumblrs.js').sites;
const birbsites = require('../birbtumblrs.js').sites;
const duccsites = require('../ducctumblrs.js').sites;

// Heroku workaround
const http = require('http');

const server = http.createServer( (req, res) => {
	res.writeHead(200, {'Content-Type': 'text/plain'});
})
server.listen( process.env.PORT );

var app = new Clapp.App({
  name: cfg.name,
  desc: pkg.description,
  prefix: cfg.prefix,
  version: pkg.version,
  onReply: (msg, context) => {
    // Fired when input is needed to be shown to the user.

    context.msg.reply('\n' + msg).then(bot_response => {
      if (cfg.deleteAfterReply.enabled) {
        context.msg.delete(cfg.deleteAfterReply.time)
          .then(msg => console.log(`Deleted message from ${msg.author}`))
          .catch(console.log);
        bot_response.delete(cfg.deleteAfterReply.time)
          .then(msg => console.log(`Deleted message from ${msg.author}`))
          .catch(console.log);
      }
    });
  }
});

// Load every command in the commands folder
fs.readdirSync('./lib/commands/').forEach(file => {
  app.addCommand(require("./commands/" + file));
});

bot.on('message', msg => {
  // Fired when someone sends a message
  if (!msg.content.startsWith('!')) return;
  if (msg.author.bot) return;

  if (msg.content === '!food') {
		getRandomPhoto( msg, foodsites );
  }

  else if (msg.content === '!shibe') {
  		getRandomPhoto( msg, shibesites );
  }

  else if (msg.content === '!birb') {
  		getRandomPhoto( msg, birbsites );
  }

  else if (msg.content === '!ducc') {
  		getRandomPhoto( msg, duccsites );
  }

  if (app.isCliSentence(msg.content)) {
    app.parseInput(msg.content, {
      msg: msg
      // Keep adding properties to the context as you need them
    });
  }

});

bot.login(cfg.token).then(() => {
  console.log('Discord bot running!');
});

function getRandomPhoto( msg, sites, callback ) {

	var site = sites[Math.floor(Math.random()*sites.length)];
	var blog = new tumblrLib.Blog(site, cfg.tumblr_OAuth );

	console.log( '------\nSite: ' + site + '\n' );
	var url = getURL( blog, function( url ) {
		msg.reply( url );
	});
};

function getURL( blog, offset, callback ) {

	var offset = 0;
	blog.photo( {type: 'photo', limit: '1'}, function( error, response, callback ) {

		if( !response ) {
			return callback( "Try again later." );
		}

		console.log( 'Offset: ' + offset + '\n');

		offset = Math.floor( Math.random() * response.total_posts );

		console.log( 'Offset: ' + offset + '\n');

		blog.photo( {type: 'photo', limit: '1', offset: offset}, function(error, response, callback) {

			// pick a post
			var posts = response.posts;
			var url = posts[0].photos[0].original_size.url;
			console.log( 'url: ' + url );
			return callback( url );
		});
	});

};<|endoftext|>


<commit_before>// Load modules

var Fs = require('fs');
var Path = require('path');
var Bossy = require('bossy');
var Glue;
var Hoek = require('hoek');

// Declare internals

var internals = {};

internals.definition = {
    c: {
        description: 'Manifest json file',
        require: true
    },
    p: {
        description: 'node_modules path'
    },
    r: {
        alias: 'require',
        description: 'A module to be required before the application is loaded',
        multiple: true
    },
    h: {
        alias: 'help',
        description: 'Show help',
        type: 'boolean'
    }
};

internals.loadExtras = function (args) {

    var extras = args.require;

    if (!extras) {
        return;
    }

    var extrasPath;
    var nodeModulesPath = Path.join(process.cwd(), 'node_modules');

    if (args.p) {
        nodeModulesPath = Path.join(Fs.realpathSync(args.p), 'node_modules');
    }

    for (var i = 0, il = extras.length; i < il; i++) {
        var extra = extras[i];
        if (!Hoek.isAbsolutePath(extra)) {
            if (extra[0] === '.') {
                extrasPath = Path.join(process.cwd(), extra);
            }
            else {
                extrasPath = Path.join(nodeModulesPath, extra);
            }
        }
        else {
            extrasPath = extra;
        }

        try {
            require(extrasPath);
        }
        catch (err) {
            console.error('Unable to require extra file: %s (%s)', extra, err.message);
            return err;
        }
    }
};

internals.getManifest = function (args) {

    var manifest = null;
    var manifestPath = Path.resolve(process.cwd(), args.c);

    try {
        manifest = require(manifestPath);
    }
    catch (err) {
        console.log('Failed loading configuration file: %s (%s)', args.c, err.message);
        return err;
    }

    internals.parseEnv(manifest);

    return manifest;
};

internals.loadPacks = function (args, manifest, callback) {

    var options = {};

    if (!args.p) {
        return callback(null, options);
    }

    Fs.realpath(args.p, function (err, path) {

        if (err) {
            return callback(err);
        }

        options = { relativeTo: path };
        callback(null, options);
    });
};

internals.parseEnv = function (manifest) {

    if (!manifest ||
        typeof manifest !== 'object') {

        return;
    }

    Object.keys(manifest).forEach(function (key) {

        var value = manifest[key];
        if (typeof value === 'string' &&
            value.indexOf('$env.') === 0) {

            manifest[key] = process.env[value.slice(5)];
        }
        else {
            internals.parseEnv(value);
        }
    });
};

exports.start = function (options) {

    var args = Bossy.parse(internals.definition, {
        argv: options.args
    });

    if (args instanceof Error) {
        console.error(Bossy.usage(internals.definition, 'rejoice -c manifest.json [-p node_modules_path -r pre_load_module]'));
        return process.exit(1);
    }

    if (args.h) {
        console.log(Bossy.usage(internals.definition, 'rejoice -c manifest.json [-p node_modules_path -r pre_load_module]'));
        return process.exit(1);
    }

    if (internals.loadExtras(args) instanceof Error) {
        return process.exit(1);
    }

    var manifest = internals.getManifest(args);

    if (manifest instanceof Error) {
        return process.exit(1);
    }

    internals.loadPacks(args, manifest, function (err, packOptions) {

        Glue = require('glue');

        if (err) {
            console.error(err);
            return process.exit(1);
        }

        Glue.compose(manifest, packOptions, function (err, server) {

            Hoek.assert(!err, 'Failed loading plugins: ' + (err && err.message));

            server.start(function (err) {

                Hoek.assert(!err, 'Failed starting server: ' + (err && err.message));

                // Use kill -s QUIT {pid} to kill the servers gracefully

                process.once('SIGQUIT', function () {

                    server.stop(function () {

                        process.exit(0);
                    });
                });

                // Use kill -s SIGUSR2 {pid} to restart the servers

                process.on('SIGUSR2', function () {

                    console.log('Stopping...');
                    server.stop(function () {

                        console.log('Starting...');
                        exports.start(options);
                    });
                });
            });
        });
    });
};
<commit_msg>move var inside<commit_after>// Load modules

var Fs = require('fs');
var Path = require('path');
var Bossy = require('bossy');
var Hoek = require('hoek');

// Declare internals

var internals = {};

internals.definition = {
    c: {
        description: 'Manifest json file',
        require: true
    },
    p: {
        description: 'node_modules path'
    },
    r: {
        alias: 'require',
        description: 'A module to be required before the application is loaded',
        multiple: true
    },
    h: {
        alias: 'help',
        description: 'Show help',
        type: 'boolean'
    }
};

internals.loadExtras = function (args) {

    var extras = args.require;

    if (!extras) {
        return;
    }

    var extrasPath;
    var nodeModulesPath = Path.join(process.cwd(), 'node_modules');

    if (args.p) {
        nodeModulesPath = Path.join(Fs.realpathSync(args.p), 'node_modules');
    }

    for (var i = 0, il = extras.length; i < il; i++) {
        var extra = extras[i];
        if (!Hoek.isAbsolutePath(extra)) {
            if (extra[0] === '.') {
                extrasPath = Path.join(process.cwd(), extra);
            }
            else {
                extrasPath = Path.join(nodeModulesPath, extra);
            }
        }
        else {
            extrasPath = extra;
        }

        try {
            require(extrasPath);
        }
        catch (err) {
            console.error('Unable to require extra file: %s (%s)', extra, err.message);
            return err;
        }
    }
};

internals.getManifest = function (args) {

    var manifest = null;
    var manifestPath = Path.resolve(process.cwd(), args.c);

    try {
        manifest = require(manifestPath);
    }
    catch (err) {
        console.log('Failed loading configuration file: %s (%s)', args.c, err.message);
        return err;
    }

    internals.parseEnv(manifest);

    return manifest;
};

internals.loadPacks = function (args, manifest, callback) {

    var options = {};

    if (!args.p) {
        return callback(null, options);
    }

    Fs.realpath(args.p, function (err, path) {

        if (err) {
            return callback(err);
        }

        options = { relativeTo: path };
        callback(null, options);
    });
};

internals.parseEnv = function (manifest) {

    if (!manifest ||
        typeof manifest !== 'object') {

        return;
    }

    Object.keys(manifest).forEach(function (key) {

        var value = manifest[key];
        if (typeof value === 'string' &&
            value.indexOf('$env.') === 0) {

            manifest[key] = process.env[value.slice(5)];
        }
        else {
            internals.parseEnv(value);
        }
    });
};

exports.start = function (options) {

    var args = Bossy.parse(internals.definition, {
        argv: options.args
    });

    if (args instanceof Error) {
        console.error(Bossy.usage(internals.definition, 'rejoice -c manifest.json [-p node_modules_path -r pre_load_module]'));
        return process.exit(1);
    }

    if (args.h) {
        console.log(Bossy.usage(internals.definition, 'rejoice -c manifest.json [-p node_modules_path -r pre_load_module]'));
        return process.exit(1);
    }

    if (internals.loadExtras(args) instanceof Error) {
        return process.exit(1);
    }

    var manifest = internals.getManifest(args);

    if (manifest instanceof Error) {
        return process.exit(1);
    }

    internals.loadPacks(args, manifest, function (err, packOptions) {

        var Glue = require('glue');

        if (err) {
            console.error(err);
            return process.exit(1);
        }

        Glue.compose(manifest, packOptions, function (err, server) {

            Hoek.assert(!err, 'Failed loading plugins: ' + (err && err.message));

            server.start(function (err) {

                Hoek.assert(!err, 'Failed starting server: ' + (err && err.message));

                // Use kill -s QUIT {pid} to kill the servers gracefully

                process.once('SIGQUIT', function () {

                    server.stop(function () {

                        process.exit(0);
                    });
                });

                // Use kill -s SIGUSR2 {pid} to restart the servers

                process.on('SIGUSR2', function () {

                    console.log('Stopping...');
                    server.stop(function () {

                        console.log('Starting...');
                        exports.start(options);
                    });
                });
            });
        });
    });
};
<|endoftext|>


<commit_before>/*
 * Vecna
 * https://github.com/eburgos/Vecna
 *
 * Copyright (c) 2015 goliatone
 * Licensed under the MIT license.
 */

'use strict';

var debug = require('debug')('vcn');
var extend = require('gextend');
var _inherit = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
var Promise = require('bluebird');
var tildify = require('tildify');
var untildify = require('untildify');
var crypto = require('crypto');
var fs = Promise.promisifyAll(require('fs'));
var tmp = require('tmp');
var awscreds = require('./get-aws-credentials');
var Spinner = require('./spinner');

var DEFAULTS = {
    autoinitialize: true,
    algorithm: 'aes-256-ctr',
    //bucket needs to be unique across users/orgs
    bucket: 'goliatone.vecna.io',
    groupId: 'secrets',
    extension: 'vcn'
};

function Vecna(config){
    EventEmitter.call(this);
    config = extend({}, this.constructor.DEFAULTS, config);

    if(config.autoinitialize ) this.init(config);
}

_inherit(Vecna, EventEmitter);

Vecna.DEFAULTS = DEFAULTS;

Vecna.prototype.init = function(config){
    if(this.initialized) return;
    this.initialized = true;

    extend(this, this.constructor.DEFAULTS, config);
};

Vecna.prototype.put = function(id, password, filepath) {
    var targetpath = this.getPath(id);

    var self = this;

    return fs.readFileAsync(filepath, 'utf8').then(function(content){
        debug('content', content);

        var VO = {
            content: content,
            path: tildify(filepath),
        };

        content = JSON.stringify(VO);

        var cypher = self.encrypt(content, password);

        var tmpfile = tmp.fileSync();
        debug('tmpfile', tmpfile.name);
        debug('content', cypher);
        return fs.writeFileAsync(tmpfile.name, cypher, 'utf8').then(function(){
            return awscreds.knox(self.bucket).then(function(client){
                debug('= here', targetpath);
                return client.putFileAsync(tmpfile.name, targetpath).then(function(res){
                    // debug('DONE', res);
                    res.resume();
                }).catch(function(e){
                    console.error('ERROR putFileAsync', e);
                    return e;
                });
            }).catch(function(e){
                //TODO: Make sure we get an error code from credential finder
                console.error('AWS credentials not found:');
                console.error('Ensure you have one of the following:');
                console.error('A valid ini file in ~/.aws/credentials with a default profile');
                console.error('A valid ini file in ~/.aws/config with a default profile');
                console.error('If you want to use a different profile set AMAZON_PROFILE env');
                console.error('');
                console.error('If you are using env vars:');
                console.error('AWS_ACCESS_KEY_ID, AMAZON_ACCESS_KEY_ID, AWS_ACCESS_KEY');
                console.error('AWS_SECRET_ACCESS_KEY, AMAZON_SECRET_ACCESS_KEY, AWS_SECRET_KEY');
                console.error('AWS_SESSION_TOKEN, AMAZON_SESSION_TOKEN');
                console.error('AWS_REGION, AMAZON_REGION, AWS_DEFAULT_REGION');
                console.error('');
                console.error('You can also load credentials form EC2 metadata');
                console.error('');
                debug(e);
                return e;
            });
        }).catch(function(e){
            console.error('ERRR fsWriteAsync', e);
            return e;
        });
    });
};

Vecna.prototype.get = function(id, password, filepath){
    var targetpath = this.getPath(id);

    var self = this;

    return awscreds.knox(self.bucket).then(function(client){
        return client.getFileAsync(targetpath).then(function(res){

            return new Promise(function(resolve, reject){
                //TODO: Handle all the non OK status codes!
                if(res.statusCode > 400){
                    return reject(new Error('Failed request: StatusCode ' + res.statusCode));
                }

                res.setEncoding('utf8');
                var data = '';

                res.on('data', function(chunk){
                    data += chunk;
                });

                res.on('end', function(){
                    data = self.decrypt(data, password);
                    debug('data');

                    var VO = JSON.parse(data);
                    VO.path = untildify(VO.path || '');

                    fs.writeFileAsync(filepath, VO.content).then(function(){
                        resolve(VO.content);
                    }).catch(function(e){
                        reject(e);
                    });
                });

                res.on('error', function(err){
                    reject(err);
                });
            });
        }).catch(function(e){
            console.log('ERROR 2', e);
        });
    }).catch(function(e){
        console.log('ERROR', e);
    });
};

Vecna.prototype.list = function(id, password){
    var self = this;

    return awscreds.knox(self.bucket).then(function(client){
        return client.listAsync({ prefix: self.groupId }).then(function(data){
            return data.Contents;
        });
    });
};

Vecna.prototype.del = function(id, password){
    //TODO: do we need a way to secure deletes? or simply by having
    //aws credentials to access the bucket we are cleared?
    var targetpath =  '/' + this.getPath(id);

    return awscreds.knox(this.bucket).then(function(client){
        return client.deleteFileAsync(targetpath).then(function(res){
            //TODO: Handle all the non OK status codes!
            if(res.statusCode === 204) {
                console.log(Object.keys(res));
                console.log(res.req.url, res.statusMessage)
                return Promise.reject(new Error('File "'+ targetpath + '" not found. ' + res.statusMessage));
            }

            console.log(res.statusCode);
            console.log('File %s deleted' , targetpath);
            res.resume();
        }).catch(function(err){
            console.error(err);
        });
    });
};

Vecna.prototype.encrypt = function(content, password){
    var cipher = crypto.createCipher( this.algorithm, password);
    var crypted = cipher.update(content,'utf8','hex');
    crypted += cipher.final('hex');
    return crypted;
};

Vecna.prototype.decrypt = function(content, password){
    var decipher = crypto.createDecipher( this.algorithm, password);
    var dec = decipher.update(content, 'hex', 'utf8');
    dec += decipher.final('utf8');
    return dec;
};

Vecna.prototype.getPath = function(id){
    return this.groupId + '/' + id + '.' + this.extension;
};

Vecna.prototype.logger = console;

/**
 * Exports module
 */
module.exports = Vecna;

Vecna.exec = function(command, options){
    if(!command.match(/put|get|del|list/)) Promise.reject(new Error('Command not supported'));

    var config = extract(options, Object.keys(Vecna.DEFAULTS));
    var vcn = new Vecna(config);

    var promise,
        spinner = new Spinner();

    switch (command) {
        case 'put':
            promise = vcn.put(options.id, options.password, options.filepath);
        break;
        case 'get':
            promise = vcn.get(options.id, options.password, options.filepath);
        break;
        case 'del':
            promise = vcn.del(options.id, options.password);
        break;
        case 'list':
            promise = vcn.list(options.id, options.password);
        break;
    }

    promise.then(function(){
        spinner.stop();
    });

    return promise;
};

function extract(src, keys){
    return keys.reduce(function(out, key){
        if(src.hasOwnProperty(key)) out[key] = src[key];
        return out;
    }, {});
}
<commit_msg>handle error responses<commit_after>/*
 * Vecna
 * https://github.com/eburgos/Vecna
 *
 * Copyright (c) 2015 goliatone
 * Licensed under the MIT license.
 */

'use strict';

var debug = require('debug')('vcn');
var extend = require('gextend');
var _inherit = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
var Promise = require('bluebird');
var tildify = require('tildify');
var untildify = require('untildify');
var crypto = require('crypto');
var fs = Promise.promisifyAll(require('fs'));
var tmp = require('tmp');
var awscreds = require('./get-aws-credentials');
var Spinner = require('./spinner');

var DEFAULTS = {
    autoinitialize: true,
    algorithm: 'aes-256-ctr',
    //bucket needs to be unique across users/orgs
    bucket: 'goliatone.vecna.io',
    groupId: 'secrets',
    extension: 'vcn'
};

function Vecna(config){
    EventEmitter.call(this);
    config = extend({}, this.constructor.DEFAULTS, config);

    if(config.autoinitialize ) this.init(config);
}

_inherit(Vecna, EventEmitter);

Vecna.DEFAULTS = DEFAULTS;

Vecna.prototype.init = function(config){
    if(this.initialized) return;
    this.initialized = true;

    extend(this, this.constructor.DEFAULTS, config);
};

Vecna.prototype.put = function(id, password, filepath) {
    var targetpath = this.getPath(id);

    var self = this;

    return fs.readFileAsync(filepath, 'utf8').then(function(content){
        debug('content', content);

        var VO = {
            content: content,
            path: tildify(filepath),
        };

        content = JSON.stringify(VO);

        var cypher = self.encrypt(content, password);

        var tmpfile = tmp.fileSync();
        debug('tmpfile', tmpfile.name);
        debug('content', cypher);
        return fs.writeFileAsync(tmpfile.name, cypher, 'utf8').then(function(){
            return awscreds.knox(self.bucket).then(function(client){
                debug('= here', targetpath);
                return client.putFileAsync(tmpfile.name, targetpath).then(function(res){
                    if(res.statusCode > 300){
                        return Promise.reject(new Error('Failed request: StatusCode ' + res.statusCode + '. ' + res.statusMessage));
                    }

                    if(res.statusCode === 204) {
                        console.log(Object.keys(res));
                        console.log(res.req.url, res.statusMessage)
                        return Promise.reject(new Error('File "'+ targetpath + '" not found. ' + res.statusMessage));
                    }

                    res.resume();
                }).catch(function(e){
                    console.error('ERROR putFileAsync', e);
                    return e;
                });
            }).catch(function(e){
                //TODO: Make sure we get an error code from credential finder
                console.error('AWS credentials not found:');
                console.error('Ensure you have one of the following:');
                console.error('A valid ini file in ~/.aws/credentials with a default profile');
                console.error('A valid ini file in ~/.aws/config with a default profile');
                console.error('If you want to use a different profile set AMAZON_PROFILE env');
                console.error('');
                console.error('If you are using env vars:');
                console.error('AWS_ACCESS_KEY_ID, AMAZON_ACCESS_KEY_ID, AWS_ACCESS_KEY');
                console.error('AWS_SECRET_ACCESS_KEY, AMAZON_SECRET_ACCESS_KEY, AWS_SECRET_KEY');
                console.error('AWS_SESSION_TOKEN, AMAZON_SESSION_TOKEN');
                console.error('AWS_REGION, AMAZON_REGION, AWS_DEFAULT_REGION');
                console.error('');
                console.error('You can also load credentials form EC2 metadata');
                console.error('');
                debug(e);
                return e;
            });
        }).catch(function(e){
            console.error('ERRR fsWriteAsync', e);
            return e;
        });
    });
};

Vecna.prototype.get = function(id, password, filepath){
    var targetpath = this.getPath(id);

    var self = this;

    return awscreds.knox(self.bucket).then(function(client){
        return client.getFileAsync(targetpath).then(function(res){

            return new Promise(function(resolve, reject){
                //TODO: Handle all the non OK status codes!
                if(res.statusCode > 300){
                    return reject(new Error('Failed request: StatusCode ' + res.statusCode + '. ' + res.statusMessage));
                }

                if(res.statusCode === 204) {
                    console.log(Object.keys(res));
                    console.log(res.req.url, res.statusMessage)
                    return Promise.reject(new Error('File "'+ targetpath + '" not found. ' + res.statusMessage));
                }

                res.setEncoding('utf8');
                var data = '';

                res.on('data', function(chunk){
                    data += chunk;
                });

                res.on('end', function(){
                    data = self.decrypt(data, password);
                    debug('data');

                    var VO = JSON.parse(data);
                    VO.path = untildify(VO.path || '');

                    fs.writeFileAsync(filepath, VO.content).then(function(){
                        resolve(VO.content);
                    }).catch(function(e){
                        reject(e);
                    });
                });

                res.on('error', function(err){
                    reject(err);
                });
            });
        }).catch(function(e){
            console.log('ERROR 2', e);
        });
    }).catch(function(e){
        console.log('ERROR', e);
    });
};

Vecna.prototype.list = function(id, password){
    var self = this;

    return awscreds.knox(self.bucket).then(function(client){
        return client.listAsync({ prefix: self.groupId }).then(function(data){
            return data.Contents;
        });
    });
};

Vecna.prototype.del = function(id, password){
    //TODO: do we need a way to secure deletes? or simply by having
    //aws credentials to access the bucket we are cleared?
    var targetpath =  '/' + this.getPath(id);

    return awscreds.knox(this.bucket).then(function(client){
        return client.deleteFileAsync(targetpath).then(function(res){

            if(res.statusCode > 300){
                return Promise.reject(new Error('Failed request: StatusCode ' + res.statusCode + '. ' + res.statusMessage));
            }

            if(res.statusCode === 204) {
                console.log(Object.keys(res));
                console.log(res.req.url, res.statusMessage)
                return Promise.reject(new Error('File "'+ targetpath + '" not found. ' + res.statusMessage));
            }

            console.log(res.statusCode);
            console.log('File %s deleted' , targetpath);
            res.resume();
        }).catch(function(err){
            console.error(err);
        });
    });
};

Vecna.prototype.encrypt = function(content, password){
    var cipher = crypto.createCipher( this.algorithm, password);
    var crypted = cipher.update(content,'utf8','hex');
    crypted += cipher.final('hex');
    return crypted;
};

Vecna.prototype.decrypt = function(content, password){
    var decipher = crypto.createDecipher( this.algorithm, password);
    var dec = decipher.update(content, 'hex', 'utf8');
    dec += decipher.final('utf8');
    return dec;
};

Vecna.prototype.getPath = function(id){
    return this.groupId + '/' + id + '.' + this.extension;
};

Vecna.prototype.logger = console;

/**
 * Exports module
 */
module.exports = Vecna;

Vecna.exec = function(command, options){
    if(!command.match(/put|get|del|list/)) Promise.reject(new Error('Command not supported'));

    var config = extract(options, Object.keys(Vecna.DEFAULTS));
    var vcn = new Vecna(config);

    var promise,
        spinner = new Spinner();

    switch (command) {
        case 'put':
            promise = vcn.put(options.id, options.password, options.filepath);
        break;
        case 'get':
            promise = vcn.get(options.id, options.password, options.filepath);
        break;
        case 'del':
            promise = vcn.del(options.id, options.password);
        break;
        case 'list':
            promise = vcn.list(options.id, options.password);
        break;
    }

    promise.then(function(){
        spinner.stop();
    });

    return promise;
};

function extract(src, keys){
    return keys.reduce(function(out, key){
        if(src.hasOwnProperty(key)) out[key] = src[key];
        return out;
    }, {});
}
<|endoftext|>


<commit_before>var termops = require('./util/termops'),
    ops = require('./util/ops'),
    _ = require('underscore'),
    queue = require('queue-async'),
    DEBUG = process.env.DEBUG;

module.exports = index;
module.exports.loadDoc = loadDoc;
module.exports.assignParts = assignParts;
module.exports.generateFrequency = generateFrequency;

// # Index
// @param {Object} source - a Carmen source
// @param {Array} docs - an array of documents
// @param {Function} callback
function index(source, docs, callback) {

    // First pass over docs.
    // - Creates termsets (one or more arrays of termids) from document text.
    // - Tallies frequency of termids against current frequencies compiling a
    //   final in-memory frequency count of all terms involved with this set of
    //   documents to be indexed.
    // - Stores new frequencies.

    docs = assignParts(docs);
    var freq = generateFrequency(docs);

    // Ensures all shards are loaded.
    var ids = Object.keys(freq).map(function(v) { return parseInt(v, 10); });
    source._geocoder.getall(source.getGeocoderData.bind(source), 'freq', ids, function(err) {
        if (err) return callback(err);
        for (var i = 0; i < ids.length; i++) {
            var id = ids[i];
            freq[id][0] = (source._geocoder.get('freq', id) || [0])[0] + freq[id][0];
            source._geocoder.set('freq', id, freq[id]);
        }
        indexDocs(freq[0], freq, callback);
    });

    // Second pass over docs.
    // - Create term => docid index. Uses calculated frequencies to index only
    //   significant terms for each document.
    // - Create id => grid zxy index.
    function indexDocs(approxdocs, freq, callback) {
        var patch = { grid: {}, term: {}, phrase: {}, degen: {}, feature: {} };
        var degenerated = {};

        for (var i = 0; i < docs.length; i++) loadDoc(docs[i], freq, patch, degenerated);

        var q = queue(500);
        _(patch).each(setParts);
        q.awaitAll(callback);

        function setParts(data, type) {
            q.defer(function(data, type, callback) {
                var ids = Object.keys(data);
                var cache = type === 'feature' ? source._features : source._geocoder;
                cache.getall(source.getGeocoderData.bind(source), type, ids, function(err) {
                    if (err) return callback(err);
                    for (var i = 0; i < ids.length; i++) {
                        var id = ids[i];
                        // This merges new entries on top of old ones.
                        switch (type) {
                        case 'term':
                        case 'grid':
                        case 'degen':
                            var current = cache.get(type, id) || [];
                            current.push.apply(current, data[id]);
                            cache.set(type, id, current);
                            break;
                        case 'phrase':
                        case 'feature':
                            cache.set(type, id, data[id]);
                            break;
                        }
                    }
                    callback();
                });
            }, data, type);
        }
    }
};

function loadDoc(doc, freq, patch, degenerated) {
    doc.doc.id = doc.id;
    doc.hash = termops.feature(doc.id.toString());
    doc.zxy = doc.zxy || [];
    for (var i = 0; i < doc.zxy.length; i++) {
        doc.zxy[i] = ops.zxy(doc.hash, doc.zxy[i]);
    }

    patch.feature[doc.hash] = patch.feature[doc.hash] || {};
    patch.feature[doc.hash][doc.id] = doc.doc;

    var phrases = doc.phrases;
    var termsets = doc.termsets;
    var termsmaps = doc.termsmaps;

    phrases.forEach(function(id, x) {
        patch.phrase[id] = patch.phrase[id] || termsets[x];
        patch.grid[id] = patch.grid[id] || [];
        patch.grid[id].push.apply(patch.grid[id], doc.zxy);
    });

    termsets.forEach(loadTerm);

    function loadTerm(terms, x) {
        var id;
        var termsmap = termsmaps[x];
        var name = phrases[x];
        var weights = [];
        var total = 0;
        var limit = Math.floor(Math.sqrt(terms.length));

        for (var i = 0; i < terms.length; i++) {
            id = terms[i];
            var weight = Math.log(1 + freq[0][0]/freq[id][0]);
            weights.push([id, weight]);
            total += weight;

            // Degenerate terms are indexed for all terms
            // (not just significant ones).
            if (degenerated[id]) continue;
            degenerated[id] = true;
            var degens = termops.degens(termsmap[id]);
            var keys = Object.keys(degens);
            for (var j = 0; j < keys.length; j++) {
                var d = keys[j];
                patch.degen[d] = patch.degen[d] || [];
                patch.degen[d].push(degens[d]);
            }
        }

        // Limit indexing to the *most* significant terms for a
        // document. Currently uses rough heuristic (floor+sqrt) to
        // determine how many of the top words to grab.
        weights.sort(function(a,b) {
            return a[1] > b[1] ? -1 : a[1] < b[1] ? 1 : 0;
        });
        var sigterms = [];
        for (i = 0; i < limit; i++) sigterms.push(weights[i][0]);

        // Debug significant term selection.
        if (DEBUG) {
            var debug = termsmap;
            var oldtext = terms.map(function(id) { return debug[id]; }).join(' ');
            var sigtext = sigterms.map(function(id) { return debug[id]; }).join(' ');
            if (oldtext !== sigtext)  console.log('%s => %s', oldtext, sigtext);
        }

        for (i = 0; i < sigterms.length; i++) {
            id = sigterms[i];
            patch.term[id] = patch.term[id] || [];
            patch.term[id].push(name);
        }
    }
}

function assignParts(docs) {

    for (var i = 0; i < docs.length; i++) {
        var doc = docs[i],
            phrases = [],
            termsets = [],
            termsmaps = [],
            texts = doc.text.split(',');

        for (var x = 0; x < texts.length; x++) {
            var tokens = termops.tokenize(texts[x]);
            if (!tokens.length) continue;
            phrases.push(termops.phrase(tokens));
            termsets.push(termops.terms(tokens));
            termsmaps.push(termops.termsMap(tokens));
        }

        doc.phrases = phrases;
        doc.termsets = termsets;
        doc.termsmaps = termsmaps;
    }

    return docs;
}

function generateFrequency(docs) {
    var freq = {};

    // Uses freq[0] as a convention for storing total # of docs.
    // @TODO determine whether 0 can really ever be a relevant term
    // when using fnv1a.
    freq[0] = [0];
    for (var i = 0; i < docs.length; i++) {
        var termsets = docs[i].termsets;
        for (var j = 0; j < termsets.length; j++) {
            var terms = termsets[j];
            for (var k = 0; k < terms.length; k++) {
                var id = terms[k];
                freq[id] = freq[id] || [0];
                freq[id][0]++;
                freq[0][0]++;
            }
        }
    }

    return freq;
}
<commit_msg>Opimization: simplify how we get to heuristic value.<commit_after>var termops = require('./util/termops'),
    ops = require('./util/ops'),
    _ = require('underscore'),
    queue = require('queue-async'),
    DEBUG = process.env.DEBUG;

module.exports = index;
module.exports.loadDoc = loadDoc;
module.exports.assignParts = assignParts;
module.exports.generateFrequency = generateFrequency;

// # Index
// @param {Object} source - a Carmen source
// @param {Array} docs - an array of documents
// @param {Function} callback
function index(source, docs, callback) {

    // First pass over docs.
    // - Creates termsets (one or more arrays of termids) from document text.
    // - Tallies frequency of termids against current frequencies compiling a
    //   final in-memory frequency count of all terms involved with this set of
    //   documents to be indexed.
    // - Stores new frequencies.

    docs = assignParts(docs);
    var freq = generateFrequency(docs);

    // Ensures all shards are loaded.
    var ids = Object.keys(freq).map(function(v) { return parseInt(v, 10); });
    source._geocoder.getall(source.getGeocoderData.bind(source), 'freq', ids, function(err) {
        if (err) return callback(err);
        for (var i = 0; i < ids.length; i++) {
            var id = ids[i];
            freq[id][0] = (source._geocoder.get('freq', id) || [0])[0] + freq[id][0];
            source._geocoder.set('freq', id, freq[id]);
        }
        indexDocs(freq[0], freq, callback);
    });

    // Second pass over docs.
    // - Create term => docid index. Uses calculated frequencies to index only
    //   significant terms for each document.
    // - Create id => grid zxy index.
    function indexDocs(approxdocs, freq, callback) {
        var patch = { grid: {}, term: {}, phrase: {}, degen: {}, feature: {} };
        var degenerated = {};

        for (var i = 0; i < docs.length; i++) loadDoc(docs[i], freq, patch, degenerated);

        var q = queue(500);
        _(patch).each(setParts);
        q.awaitAll(callback);

        function setParts(data, type) {
            q.defer(function(data, type, callback) {
                var ids = Object.keys(data);
                var cache = type === 'feature' ? source._features : source._geocoder;
                cache.getall(source.getGeocoderData.bind(source), type, ids, function(err) {
                    if (err) return callback(err);
                    for (var i = 0; i < ids.length; i++) {
                        var id = ids[i];
                        // This merges new entries on top of old ones.
                        switch (type) {
                        case 'term':
                        case 'grid':
                        case 'degen':
                            var current = cache.get(type, id) || [];
                            current.push.apply(current, data[id]);
                            cache.set(type, id, current);
                            break;
                        case 'phrase':
                        case 'feature':
                            cache.set(type, id, data[id]);
                            break;
                        }
                    }
                    callback();
                });
            }, data, type);
        }
    }
};

function loadDoc(doc, freq, patch, degenerated) {
    doc.doc.id = doc.id;
    doc.hash = termops.feature(doc.id.toString());
    doc.zxy = doc.zxy || [];
    for (var i = 0; i < doc.zxy.length; i++) {
        doc.zxy[i] = ops.zxy(doc.hash, doc.zxy[i]);
    }

    patch.feature[doc.hash] = patch.feature[doc.hash] || {};
    patch.feature[doc.hash][doc.id] = doc.doc;

    var phrases = doc.phrases;
    var termsets = doc.termsets;
    var termsmaps = doc.termsmaps;

    phrases.forEach(function(id, x) {
        patch.phrase[id] = patch.phrase[id] || termsets[x];
        patch.grid[id] = patch.grid[id] || [];
        patch.grid[id].push.apply(patch.grid[id], doc.zxy);
    });

    termsets.forEach(loadTerm);

    function loadTerm(terms, x) {
        var id;
        var termsmap = termsmaps[x];
        var name = phrases[x];
        var weights = [];
        var limit = terms.length > 3 ? 2 : 1;

        for (var i = 0; i < terms.length; i++) {
            id = terms[i];
            var weight = Math.log(1 + freq[0][0]/freq[id][0]);
            weights.push([id, weight]);

            // Degenerate terms are indexed for all terms
            // (not just significant ones).
            if (degenerated[id]) continue;
            degenerated[id] = true;
            var degens = termops.degens(termsmap[id]);
            var keys = Object.keys(degens);
            for (var j = 0; j < keys.length; j++) {
                var d = keys[j];
                patch.degen[d] = patch.degen[d] || [];
                patch.degen[d].push(degens[d]);
            }
        }

        // Limit indexing to the *most* significant terms for a
        // document. Currently uses rough heuristic (floor+sqrt) to
        // determine how many of the top words to grab.
        weights.sort(function(a,b) {
            return a[1] > b[1] ? -1 : a[1] < b[1] ? 1 : 0;
        });
        var sigterms = [];
        for (i = 0; i < limit; i++) sigterms.push(weights[i][0]);

        // Debug significant term selection.
        if (DEBUG) {
            var debug = termsmap;
            var oldtext = terms.map(function(id) { return debug[id]; }).join(' ');
            var sigtext = sigterms.map(function(id) { return debug[id]; }).join(' ');
            if (oldtext !== sigtext)  console.log('%s => %s', oldtext, sigtext);
        }

        for (i = 0; i < sigterms.length; i++) {
            id = sigterms[i];
            patch.term[id] = patch.term[id] || [];
            patch.term[id].push(name);
        }
    }
}

function assignParts(docs) {

    for (var i = 0; i < docs.length; i++) {
        var doc = docs[i],
            phrases = [],
            termsets = [],
            termsmaps = [],
            texts = doc.text.split(',');

        for (var x = 0; x < texts.length; x++) {
            var tokens = termops.tokenize(texts[x]);
            if (!tokens.length) continue;
            phrases.push(termops.phrase(tokens));
            termsets.push(termops.terms(tokens));
            termsmaps.push(termops.termsMap(tokens));
        }

        doc.phrases = phrases;
        doc.termsets = termsets;
        doc.termsmaps = termsmaps;
    }

    return docs;
}

function generateFrequency(docs) {
    var freq = {};

    // Uses freq[0] as a convention for storing total # of docs.
    // @TODO determine whether 0 can really ever be a relevant term
    // when using fnv1a.
    freq[0] = [0];
    for (var i = 0; i < docs.length; i++) {
        var termsets = docs[i].termsets;
        for (var j = 0; j < termsets.length; j++) {
            var terms = termsets[j];
            for (var k = 0; k < terms.length; k++) {
                var id = terms[k];
                freq[id] = freq[id] || [0];
                freq[id][0]++;
                freq[0][0]++;
            }
        }
    }

    return freq;
}
<|endoftext|>


<commit_before>const events =  require('events');
const PubSub = require('@google-cloud/pubsub');
const path = require('path');
const uuid = require('uuid');

const namePrefix = 'parse-server';

let emitter = new events.EventEmitter();

if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {
  throw "set GOOGLE_APPLICATION_CREDENTIALS variable (see https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/0.8.0/guides/authentication)";
}

if (!process.env.GCLOUD_PROJECT) {
  throw "set GCLOUD_PROJECT variable (see https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/0.8.0/guides/authentication)";
}

/**
 * In order to use gcp pub/sub module we must provide 2 env. variables
 * GCP_PROJECT_ID - the project id on GCP
 * GCP_KEYFILE_PATH - path where the google service account key is located
 */
const pubsubClient = PubSub();

class Publisher {

  constructor(emitter) {
    this.emitter = emitter;

    // process.on('SIGNINT',function(){
    //   process.exit();
    // });

    // process.on('SIGTERM',function(){
    //   process.exit();
    // });

  }

  publish(channel, message) {

    let topicName = `${namePrefix}-${channel}`;
    const topic = pubsubClient.topic(topicName);

    topic.publish(message, (err, messageIds) => {
      if (err) {
        return;
      }
    });
  }
};

class Subscriber extends events.EventEmitter {

  constructor() {
    super();
    process.on('SIGNINT',function(){
      process.exit();
    });
  }

  subscribe(channel) {

    let topicName = `${namePrefix}-${channel}`;
    const topic = pubsubClient.topic(topicName);

    /**
     * check if the topic that we want to create exist
     * if the topic not exist create a new topic based on the channel name
     * the topic name will be parse-server-{channel_name}
     *  */
    topic.exists((err, exists) => {
      if (!exists && !err) {
        topic.create((err, topic, apiResponse) => {
          if (err) {
            return;
          }
          this._createSubscription(topic,channel);
        });
      } else {
        this._createSubscription(topic,channel);
      }
    });
  }

  unsubscribe(channel) {
    // Here we should get all the subscriptions under the channel topic and unsubscribe them
  }

  _createSubscription(topic,channel) {

    const subscriptionUUID = uuid.v1();
    var subscriptionName = `${namePrefix}-${channel}-${subscriptionUUID}`;

    topic.subscribe(subscriptionName, (err, subscription) => {
      if (err) {
        console.log(`Failed to create subscription ${err}`);
        return;
      }

      console.log(`Subscription ${subscription.name} created.`);

      subscription.on('message', (message) => {
        if (message.ackId) {
          message.ack();
        }
        let topicName = `${namePrefix}-${channel}`;
        this.emit('message', channel , message.data);
      });
    });
  }
}

function createPublisher() {
  return new Publisher(emitter);
}

function createSubscriber() {
  return new Subscriber();
}

let GcpPubSub = {
  createPublisher,
  createSubscriber
}

module.exports = GcpPubSub;<commit_msg>Adds signal handler for exit<commit_after>const events =  require('events');
const PubSub = require('@google-cloud/pubsub');
const path = require('path');
const uuid = require('uuid');

const namePrefix = 'parse-server';

let emitter = new events.EventEmitter();

if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {
  throw "set GOOGLE_APPLICATION_CREDENTIALS variable (see https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/0.8.0/guides/authentication)";
}

if (!process.env.GCLOUD_PROJECT) {
  throw "set GCLOUD_PROJECT variable (see https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/0.8.0/guides/authentication)";
}

/**
 * In order to use gcp pub/sub module we must provide 2 env. variables
 * GCP_PROJECT_ID - the project id on GCP
 * GCP_KEYFILE_PATH - path where the google service account key is located
 */
const pubsubClient = PubSub();

class Publisher {

  constructor(emitter) {
    this.emitter = emitter;

    // process.on('SIGNINT',function(){
    //   process.exit();
    // });

    // process.on('SIGTERM',function(){
    //   process.exit();
    // });

  }

  publish(channel, message) {

    let topicName = `${namePrefix}-${channel}`;
    const topic = pubsubClient.topic(topicName);

    topic.publish(message, (err, messageIds) => {
      if (err) {
        return;
      }
    });
  }
};

class Subscriber extends events.EventEmitter {

  constructor() {
    super();
    process.on('SIGNINT',function(){
      process.exit();
    });
  }

  subscribe(channel) {

    let topicName = `${namePrefix}-${channel}`;
    const topic = pubsubClient.topic(topicName);

    /**
     * check if the topic that we want to create exist
     * if the topic not exist create a new topic based on the channel name
     * the topic name will be parse-server-{channel_name}
     *  */
    topic.exists((err, exists) => {
      if (!exists && !err) {
        topic.create((err, topic, apiResponse) => {
          if (err) {
            return;
          }
          this._createSubscription(topic,channel);
        });
      } else {
        this._createSubscription(topic,channel);
      }
    });
  }

  unsubscribe(channel) {
    // Here we should get all the subscriptions under the channel topic and unsubscribe them
  }

  _createSubscription(topic,channel) {

    const subscriptionUUID = uuid.v1();
    var subscriptionName = `${namePrefix}-${channel}-${subscriptionUUID}`;

    topic.subscribe(subscriptionName, (err, subscription) => {
      if (err) {
        console.log(`Failed to create subscription ${err}`);
        return;
      }

      console.log(`Subscription ${subscription.name} created.`);
      process.on('SIGTERM', () => {
        subscription.delete();
      });
      process.on('SIGINT', () => {
        subscription.delete();
      });
      subscription.on('message', (message) => {
        if (message.ackId) {
          message.ack();
        }
        let topicName = `${namePrefix}-${channel}`;
        this.emit('message', channel , message.data);
      });
    });
  }
}

function createPublisher() {
  return new Publisher(emitter);
}

function createSubscriber() {
  return new Subscriber();
}

let GcpPubSub = {
  createPublisher,
  createSubscriber
}

module.exports = GcpPubSub;<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2016 Mauro Doganieri - Nicola Del Gobbo
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the license at http://www.apache.org/licenses/LICENSE-2.0
 *
 * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
 * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
 * MERCHANTABLITY OR NON-INFRINGEMENT.
 *
 * See the Apache Version 2.0 License for specific language governing
 * permissions and limitations under the License.
 *
 * Contributors - initial API implementation:
 * Mauro Doganieri <mauro.doganieri@gmail.com>
 * Nicola Del Gobbo <nicoladelgobbo@gmail.com>
 ******************************************************************************/

'use strict';

/*!
 * Module dependencies
 */
const co = require('co');
const yahc = require('./yahc');

module.exports = {

  ENC_TYPES: yahc.ENC_TYPES,

  TIMEOUT: yahc.TIMEOUT,

  /**
   * @description This method has the responsibility to handle all GET requests
   * performed by the rest client.
   * @param {object} options Object that contains all parameters for GET method.
   * @param {string} [options.url = null] Url is a string represent the uri of
   * the request.
   * @param {object} [options.headers = null] Headers is a set of key - value of
   * all HTTP headers present in the request.
   * @param {object} [options.qs = null] Query string is a set of key - value of
   * all query parameter in the request.
   * @param {string} [options.encType = application/x-www-form-urlencoded] This
   * parameter is a string represent the encoding type for the request.
   * @param {boolean} [options.isJson = true] This parameter adds Content-type
   * application/json header and additionally the response will be automatically
   * parsed as JSON.
   * @param {number} [options.ntries = 1] This parameter represent the number of
   * attempts before to consider the request as failed.
   * @param {number} [options.timeout = 15000] This parameter represent the
   * number of seconds expressed in millisencods before to consider the request
   * as failed.
   * @typedef {Promise.<(object|Error)>} Promise
   * @returns Promise The object that represent the server response about the
   * requested resource(s) in case of resolve, while on reject it return
   * ResponseError or RestClientError.
   * @public
   */
  get({url = null,
    headers = null,
    qs = null,
    encType = this.ENC_TYPES.X_WWW_FORM_URLENCODED,
    isJson = true,
    timeout = this.TIMEOUT,
    ntries = 1
  }) {
    return co(yahc.GET({
          url: url,
          headers: headers,
          qs: qs,
          encType: encType,
          isJson: isJson,
          timeout: timeout,
          ntries: ntries
        }
      )
    );
  },

  /**
   * @description This method has the responsibility to handle all POST requests
   * performed by the rest client.
   * @param {object} options Object that contains all parameters for POST
   * method.
   * @param {string} [options.url = null] Url is a string represent the uri of
   * the requested.
   * @param {object} [options.headers = null] Headers is a set of key - value of
   *  all HTTP headers present in the request.
   * @param {object} [options.qs = null] Query string is a set of key - value of
   * all query parameter in the request.
   * @param {object} [options.body = null]
   * @param {string} options.encType = application/x-www-form-urlencoded This
   * parameter is a string represent the encoding type for the request.
   * @param {Array} [options.files = []] Array of files to upload to the server.
   * @param {number} [options.ntries = 1] This parameter represent the number of
   * attempts before to consider the request as failed.
   * @param {number} [options.timeout = 15000] This parameter represent the
   * number of seconds expressed in millisencods before to consider the request
   * as failed.
   * @typedef {Promise.<(object|Error)>} Promise
   * @returns Promise The object that represent the server response about the
   * request in case of resolve, while on reject it return ResponseError or
   * RestClientError.
   * @public
   */
  post({
    url = null,
    headers = null,
    qs = null,
    body = null,
    encType = this.ENC_TYPES.X_WWW_FORM_URLENCODED,
    isJson = true,
    files =[],
    timeout = this.TIMEOUT,
    ntries = 1
  }) {
    return co(yahc.POST({
          url: url,
          headers: headers,
          qs: qs,
          body: body,
          encType: encType,
          isJson: isJson,
          files: files,
          timeout: timeout,
          ntries: ntries
        }
      )
    );
  },

  /**
   * @description This method has the responsibility to handle all PUT requests
   * performed by the rest client.
   * @param {object} options Object that contains all parameters for PUT method.
   * @param {string} [options.url = null] Url is a string represent the uri of
   * the request.
   * @param {object} [options.headers = null] Headers is a set of key - value of
   * all HTTP headers present in the request.
   * @param {object} [options.qs = null] Query string is a set of key - value of
   * all query parameter in the request.
   * @param {object} [options.body = null]
   * @param {string} [options.encType = application/x-www-form-urlencoded] This
   * parameter is a string represent the encoding type for the request.
   * @param {Array} [options.files = []] Array of files to upload to the server.
   * @param {number} [options.ntries = 1] This parameter represent the number of
   * attempts before to consider the request as failed.
   * @param {number} [options.timeout = 15000] This parameter represent the
   * number of seconds expressed in millisencods before to consider the request
   * as failed.
   * @typedef {Promise.<(object|Error)>} Promise
   * @returns Promise The object that represent the server response about the
   * request in case of resolve, while on reject it return ResponseError or
   * RestClientError.
   * @public
   */
  put({
    url = null,
    headers = null,
    qs = null,
    body = null,
    encType = this.ENC_TYPES.X_WWW_FORM_URLENCODED,
    isJson = true,
    files =[],
    timeout = this.TIMEOUT,
    ntries = 1
  }) {
    return co(yahc.PUT({
          url: url,
          headers: headers,
          qs: qs,
          body: body,
          encType: encType,
          isJson: isJson,
          files: files,
          timeout: timeout,
          ntries: ntries
        }
      )
    );
  },

  /**
   * @description This method has the responsibility to handle all DELETE
   * requests performed by the rest client.
   * @param {object} options Object that contains all parameters for PUT method.
   * @param {string} [options.url = null] Url is a string represent the uri of
   * the request.
   * @param {object} [options.headers = null] Headers is a set of key - value of
   * all HTTP headers present in the request.
   * @param {object} [options.qs = null] Query string is a set of key - value of
   * all query parameter in the request.
   * @param {object} [options.body = null]
   * @param {string} [options.encType = application/x-www-form-urlencoded] This
   * parameter is a string represent the encoding type for the request.
   * @param {number} [options.ntries = 1] This parameter represent the number of
   * attempts before to consider the request as failed.
   * @param {number} [options.timeout = 15000] This parameter represent the
   * number of seconds expressed in millisencods before to consider the request
   * as failed.
   * @typedef {Promise.<(object|Error)>} Promise
   * @returns Promise The oobject that represent the server response about the
   * request in case of resolve, while on reject it return ResponseError or
   * RestClientError.
   * @public
   */
  delete({
    url = null,
    headers = null,
    qs = null,
    body = null,
    encType = this.ENC_TYPES.X_WWW_FORM_URLENCODED,
    isJson = true,
    timeout = this.TIMEOUT,
    ntries = 1
  }) {
    return co(yahc.DELETE({
          url: url,
          headers: headers,
          qs: qs,
          body: body,
          encType: encType,
          isJson: isJson,
          timeout: timeout,
          ntries: ntries
        }
      )
    );
  }

};<commit_msg>Added DEFAULT_TIMEOUT Added documentation comment for recent updates<commit_after>/*******************************************************************************
 * Copyright (c) 2016 Mauro Doganieri - Nicola Del Gobbo
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the license at http://www.apache.org/licenses/LICENSE-2.0
 *
 * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
 * IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
 * MERCHANTABLITY OR NON-INFRINGEMENT.
 *
 * See the Apache Version 2.0 License for specific language governing
 * permissions and limitations under the License.
 *
 * Contributors - initial API implementation:
 * Mauro Doganieri <mauro.doganieri@gmail.com>
 * Nicola Del Gobbo <nicoladelgobbo@gmail.com>
 ******************************************************************************/

'use strict';

/*!
 * Module dependencies
 */
const co = require('co');
const yahc = require('./yahc');

module.exports = {

  /**
   * @description This object represent all encoding types handled by rest
   * client and specifies how the HTTP request should be encoded.
   * @property {string} X_WWW_FORM_URLENCODED This property indicates
   * to use application/x-www-form-urlencoded as encode type.
   * @property {string} MULTIPART_FORM_DATA This property indicates
   * to use multipart/form-data as encode type.
   */
  ENC_TYPES: yahc.ENC_TYPES,

  /**
   * @description This property represents the max number of seconds in which
   * the client have to receive the response otherwise will throw an error.
   * @public
   */
  DEFAULT_TIMEOUT: yahc.TIMEOUT,

  /**
   * @description This method has the responsibility to handle all GET requests
   * performed by the rest client.
   * @param {object} options Object that contains all parameters for GET method.
   * @param {string} [options.url = null] Url is a string represent the uri of
   * the request.
   * @param {object} [options.headers = null] Headers is a set of key - value of
   * all HTTP headers present in the request.
   * @param {object} [options.qs = null] Query string is a set of key - value of
   * all query parameter in the request.
   * @param {string} [options.encType = application/x-www-form-urlencoded] This
   * parameter is a string represent the encoding type for the request.
   * @param {boolean} [options.isJson = true] This parameter adds Content-type
   * application/json header and additionally the response will be automatically
   * parsed as JSON.
   * @param {number} [options.ntries = 1] This parameter represent the number of
   * attempts before to consider the request as failed.
   * @param {number} [options.timeout = 15000] This parameter represent the
   * number of seconds expressed in millisencods before to consider the request
   * as failed.
   * @typedef {Promise.<(object|Error)>} Promise
   * @returns Promise The object that represent the server response about the
   * requested resource(s) in case of resolve, while on reject it return
   * ResponseError or RestClientError.
   * @public
   */
  get({url = null,
    headers = null,
    qs = null,
    encType = this.ENC_TYPES.X_WWW_FORM_URLENCODED,
    isJson = true,
    timeout = this.DEFAULT_TIMEOUT,
    ntries = 1
  }) {
    return co(yahc.GET({
          url: url,
          headers: headers,
          qs: qs,
          encType: encType,
          isJson: isJson,
          timeout: timeout,
          ntries: ntries
        }
      )
    );
  },

  /**
   * @description This method has the responsibility to handle all POST requests
   * performed by the rest client.
   * @param {object} options Object that contains all parameters for POST
   * method.
   * @param {string} [options.url = null] Url is a string represent the uri of
   * the requested.
   * @param {object} [options.headers = null] Headers is a set of key - value of
   *  all HTTP headers present in the request.
   * @param {object} [options.qs = null] Query string is a set of key - value of
   * all query parameter in the request.
   * @param {object} [options.body = null]
   * @param {string} options.encType = application/x-www-form-urlencoded This
   * parameter is a string represent the encoding type for the request.
   * @param {Array} [options.files = []] Array of files to upload to the server.
   * @param {number} [options.ntries = 1] This parameter represent the number of
   * attempts before to consider the request as failed.
   * @param {number} [options.timeout = 15000] This parameter represent the
   * number of seconds expressed in millisencods before to consider the request
   * as failed.
   * @typedef {Promise.<(object|Error)>} Promise
   * @returns Promise The object that represent the server response about the
   * request in case of resolve, while on reject it return ResponseError or
   * RestClientError.
   * @public
   */
  post({
    url = null,
    headers = null,
    qs = null,
    body = null,
    encType = this.ENC_TYPES.X_WWW_FORM_URLENCODED,
    isJson = true,
    files =[],
    timeout = this.DEFAULT_TIMEOUT,
    ntries = 1
  }) {
    return co(yahc.POST({
          url: url,
          headers: headers,
          qs: qs,
          body: body,
          encType: encType,
          isJson: isJson,
          files: files,
          timeout: timeout,
          ntries: ntries
        }
      )
    );
  },

  /**
   * @description This method has the responsibility to handle all PUT requests
   * performed by the rest client.
   * @param {object} options Object that contains all parameters for PUT method.
   * @param {string} [options.url = null] Url is a string represent the uri of
   * the request.
   * @param {object} [options.headers = null] Headers is a set of key - value of
   * all HTTP headers present in the request.
   * @param {object} [options.qs = null] Query string is a set of key - value of
   * all query parameter in the request.
   * @param {object} [options.body = null]
   * @param {string} [options.encType = application/x-www-form-urlencoded] This
   * parameter is a string represent the encoding type for the request.
   * @param {Array} [options.files = []] Array of files to upload to the server.
   * @param {number} [options.ntries = 1] This parameter represent the number of
   * attempts before to consider the request as failed.
   * @param {number} [options.timeout = 15000] This parameter represent the
   * number of seconds expressed in millisencods before to consider the request
   * as failed.
   * @typedef {Promise.<(object|Error)>} Promise
   * @returns Promise The object that represent the server response about the
   * request in case of resolve, while on reject it return ResponseError or
   * RestClientError.
   * @public
   */
  put({
    url = null,
    headers = null,
    qs = null,
    body = null,
    encType = this.ENC_TYPES.X_WWW_FORM_URLENCODED,
    isJson = true,
    files =[],
    timeout = this.DEFAULT_TIMEOUT,
    ntries = 1
  }) {
    return co(yahc.PUT({
          url: url,
          headers: headers,
          qs: qs,
          body: body,
          encType: encType,
          isJson: isJson,
          files: files,
          timeout: timeout,
          ntries: ntries
        }
      )
    );
  },

  /**
   * @description This method has the responsibility to handle all DELETE
   * requests performed by the rest client.
   * @param {object} options Object that contains all parameters for PUT method.
   * @param {string} [options.url = null] Url is a string represent the uri of
   * the request.
   * @param {object} [options.headers = null] Headers is a set of key - value of
   * all HTTP headers present in the request.
   * @param {object} [options.qs = null] Query string is a set of key - value of
   * all query parameter in the request.
   * @param {object} [options.body = null]
   * @param {string} [options.encType = application/x-www-form-urlencoded] This
   * parameter is a string represent the encoding type for the request.
   * @param {number} [options.ntries = 1] This parameter represent the number of
   * attempts before to consider the request as failed.
   * @param {number} [options.timeout = 15000] This parameter represent the
   * number of seconds expressed in millisencods before to consider the request
   * as failed.
   * @typedef {Promise.<(object|Error)>} Promise
   * @returns Promise The oobject that represent the server response about the
   * request in case of resolve, while on reject it return ResponseError or
   * RestClientError.
   * @public
   */
  delete({
    url = null,
    headers = null,
    qs = null,
    body = null,
    encType = this.ENC_TYPES.X_WWW_FORM_URLENCODED,
    isJson = true,
    timeout = this.DEFAULT_TIMEOUT,
    ntries = 1
  }) {
    return co(yahc.DELETE({
          url: url,
          headers: headers,
          qs: qs,
          body: body,
          encType: encType,
          isJson: isJson,
          timeout: timeout,
          ntries: ntries
        }
      )
    );
  }

};<|endoftext|>


<commit_before>/**
 * Simple client-side router
 * @module riot-route
 */

var observable = require('riot-observable')

var RE_ORIGIN = /^.+?\/+[^\/]+/,
  EVENT_LISTENER = 'EventListener',
  REMOVE_EVENT_LISTENER = 'remove' + EVENT_LISTENER,
  ADD_EVENT_LISTENER = 'add' + EVENT_LISTENER,
  HAS_ATTRIBUTE = 'hasAttribute',
  REPLACE = 'replace',
  POPSTATE = 'popstate',
  TRIGGER = 'trigger',
  win = window,
  doc = document,
  loc = win.history.location || win.location, // see html5-history-api
  prot = Router.prototype, // to minify more
  clickEvent = doc && doc.ontouchstart ? 'touchstart' : 'click',
  started = false,
  central = observable(),
  base, current

/**
 * Router class
 */
function Router() {
  this.$ = []
  observable(this) // make it observable
  central.on('stop', this.s.bind(this))
  central.on('emit', this.e.bind(this))
}

/**
 * Default parser. You can replace it via router.parser method.
 * @param {string} normalizedPath - current path (normalized)
 * @returns {array} array or object as you like
 */
function parser(normalizedPath) {
  return normalizedPath.split(/[/?#]/)
}

function normalize(path) {
  return path[REPLACE](/^\//, '')
}

/**
 * Get the part after domain name
 * @param {string} href - fullpath
 * @returns {string} path from root
 */
function getPathFromRoot(href) {
  return (href || loc.href)[REPLACE](RE_ORIGIN, '')
}

/**
 * Get the part after base
 * @param {string} href - fullpath
 * @returns {string} path from base
 */
function getPathFromBase(href) {
  return base[0] == '#'
    ? (href || loc.href).split(base)[1] || ''
    : getPathFromRoot(href)[REPLACE](base, '')
}

function emit(force) {
  var path = getPathFromBase()
  if (force || path != current) {
    central[TRIGGER]('emit', path)
    current = path
  }
}

function click(e) {
  if (
    e.which != 1 // not left click
    || e.metaKey || e.ctrlKey || e.shiftKey // or meta keys
    || e.defaultPrevented // or default prevented
  ) return

  var el = e.target
  while (el && el.nodeName != 'A') el = el.parentNode
  if (
    !el || el.nodeName != 'A' // not A tag
    || el[HAS_ATTRIBUTE]('download') // has download attr
    || !el[HAS_ATTRIBUTE]('href') // has no href attr
    || el.getAttribute('rel') == 'external' // rel is external
    || el.target && el.target != '_self' // another window or frame
    || el.href.indexOf(loc.href.match(RE_ORIGIN)[0]) == -1 // cross origin
  ) return

  if (el.href != loc.href) {
    if (el.href.split('#')[0] == loc.href.split('#')[0]) return // internal jump
    go(getPathFromBase(el.href), el.title || doc.title)
  }
  e.preventDefault()
}

/**
 * Go to the path
 * @param {string} path - destination path
 * @param {string} title - page title
 */
function go(path, title) {
  title = title || doc.title
  // browsers ignores the second parameter `title`
  history.pushState(null, title, base + path)
  // so we need to set it manually
  doc.title = title
  emit()
}

/**
 * Go to path or set action
 * a single string:                go there
 * two strings:                    go there with setting a title
 * a single function:              set an action on the default route
 * a string/RegExp and a function: set an action on the route
 * @param {(string|function)} first - path / action / filter
 * @param {(string|RegExp|function)} second - title / action
 */
prot.m = function(first, second) {
  if (first[0] && (!second || second[0])) go(first, second)
  else if (second) this.r(first, second)
  else this.r('@', first)
}

/**
 * Stop routing
 */
prot.s = function() {
  this.off('*')
}

/**
 * Emit
 * @param {string} path - path
 */
prot.e = function(path) {
  var filter, args, $ = this.$
  for (var i = 0; i < $.length; i++) {
    filter = $[i][0]
    if (filter != '@' && (args = path.match($[i][1]))) {
      args = args.slice(1)
      break
    }
  }
  if (!args) {
    filter = '@'
    args = parser(normalize(path))
  }
  this[TRIGGER].apply(null, [filter].concat(args))
}

/**
 * Register route
 * @param {string} filter - filter for matching to url
 * @param {function} action - action to register
 */
prot.r = function(filter, action) {
  this.$.push([filter, new RegExp('^' + filter[REPLACE](/\*{2,}/g, '@@')[REPLACE](/\*/g, '(\\w+)')[REPLACE](/@@/, '.*') + '$')])
  this.on(filter, action)
}

var mainRouter = new Router()
var route = mainRouter.m.bind(mainRouter)

/**
 * Create a sub router
 * @returns {function} the method of a new Router object
 */
route.create = function() {
  var newSubRouter = new Router()
  return newSubRouter.m.bind(newSubRouter)
}

/**
 * Set the base of url
 * @param {(str|RegExp)} arg - a new base or '#' or '#!'
 */
route.base = function(arg) {
  base = arg || '#'
  current = getPathFromBase() // recalculate current path
}

/** Exec routing right now **/
route.exec = function() {
  emit(true)
}

/**
 * Replace the default router to yours
 * @param {function} fn - your parser function
 */
route.parser = function(fn) {
  parser = fn
}

/**
 * Helper function to get url query as an object
 * @returns {object} parsed query
 */
route.query = function() {
  var q = {}
  loc.href[REPLACE](/[?&](.+?)=([^&]*)/g, function(_, k, v) { q[k] = v })
  return q
}

/** Stop routing **/
route.stop = function () {
  if (started) {
    win[REMOVE_EVENT_LISTENER](POPSTATE, emit)
    doc[REMOVE_EVENT_LISTENER](clickEvent, click)
    central[TRIGGER]('stop')
    started = false
  }
}

/** Start routing **/
route.start = function () {
  if (!started) {
    win[ADD_EVENT_LISTENER](POPSTATE, emit)
    doc[ADD_EVENT_LISTENER](clickEvent, click)
    started = true
  }
}

/** Autostart the router **/
route.base()
route.start()

module.exports = route
<commit_msg>Make second parser replacable<commit_after>/**
 * Simple client-side router
 * @module riot-route
 */

var observable = require('riot-observable')

var RE_ORIGIN = /^.+?\/+[^\/]+/,
  EVENT_LISTENER = 'EventListener',
  REMOVE_EVENT_LISTENER = 'remove' + EVENT_LISTENER,
  ADD_EVENT_LISTENER = 'add' + EVENT_LISTENER,
  HAS_ATTRIBUTE = 'hasAttribute',
  REPLACE = 'replace',
  POPSTATE = 'popstate',
  TRIGGER = 'trigger',
  win = window,
  doc = document,
  loc = win.history.location || win.location, // see html5-history-api
  prot = Router.prototype, // to minify more
  clickEvent = doc && doc.ontouchstart ? 'touchstart' : 'click',
  started = false,
  central = observable(),
  base, current

/**
 * Router class
 */
function Router() {
  this.$ = []
  observable(this) // make it observable
  central.on('stop', this.s.bind(this))
  central.on('emit', this.e.bind(this))
}

/**
 * Default parser. You can replace it via router.parser method.
 * @param {string} path - current path (normalized)
 * @returns {array} array
 */
function parser(path) {
  return path.split(/[/?#]/)
}

/**
 * Default parser (second). You can replace it via router.parser method.
 * @param {string} path - current path (normalized)
 * @param {string} filter - filter string (normalized)
 * @returns {array} array
 */
function secondParser(path, filter) {
  var re = new RegExp('^' + filter[REPLACE](/\*/g, '(\\w+)')[REPLACE](/\.\./, '.*') + '$')
  if (args = path.match(re)) return args.slice(1)
}

function normalize(path) {
  return path[REPLACE](/^\/|\/$/, '')
}

/**
 * Get the part after domain name
 * @param {string} href - fullpath
 * @returns {string} path from root
 */
function getPathFromRoot(href) {
  return (href || loc.href)[REPLACE](RE_ORIGIN, '')
}

/**
 * Get the part after base
 * @param {string} href - fullpath
 * @returns {string} path from base
 */
function getPathFromBase(href) {
  return base[0] == '#'
    ? (href || loc.href).split(base)[1] || ''
    : getPathFromRoot(href)[REPLACE](base, '')
}

function emit(force) {
  var path = getPathFromBase()
  if (force || path != current) {
    central[TRIGGER]('emit', path)
    current = path
  }
}

function click(e) {
  if (
    e.which != 1 // not left click
    || e.metaKey || e.ctrlKey || e.shiftKey // or meta keys
    || e.defaultPrevented // or default prevented
  ) return

  var el = e.target
  while (el && el.nodeName != 'A') el = el.parentNode
  if (
    !el || el.nodeName != 'A' // not A tag
    || el[HAS_ATTRIBUTE]('download') // has download attr
    || !el[HAS_ATTRIBUTE]('href') // has no href attr
    || el.getAttribute('rel') == 'external' // rel is external
    || el.target && el.target != '_self' // another window or frame
    || el.href.indexOf(loc.href.match(RE_ORIGIN)[0]) == -1 // cross origin
  ) return

  if (el.href != loc.href) {
    if (el.href.split('#')[0] == loc.href.split('#')[0]) return // internal jump
    go(getPathFromBase(el.href), el.title || doc.title)
  }
  e.preventDefault()
}

/**
 * Go to the path
 * @param {string} path - destination path
 * @param {string} title - page title
 */
function go(path, title) {
  title = title || doc.title
  // browsers ignores the second parameter `title`
  history.pushState(null, title, base + path)
  // so we need to set it manually
  doc.title = title
  emit()
}

/**
 * Go to path or set action
 * a single string:                go there
 * two strings:                    go there with setting a title
 * a single function:              set an action on the default route
 * a string/RegExp and a function: set an action on the route
 * @param {(string|function)} first - path / action / filter
 * @param {(string|RegExp|function)} second - title / action
 */
prot.m = function(first, second) {
  if (first[0] && (!second || second[0])) go(first, second)
  else if (second) this.r(first, second)
  else this.r('@', first)
}

/**
 * Stop routing
 */
prot.s = function() {
  this.off('*')
}

/**
 * Emit
 * @param {string} path - path
 */
prot.e = function(path) {
  this.$.concat('@').some(function(filter) {
    var args = (filter == '@' ? parser : secondParser)(normalize(path), normalize(filter))
    if (args) {
      this[TRIGGER].apply(null, [filter].concat(args))
      return true // exit from loop
    }
  }, this)
}

/**
 * Register route
 * @param {string} filter - filter for matching to url
 * @param {function} action - action to register
 */
prot.r = function(filter, action) {
  if (filter != '@') this.$.push(filter)
  this.on(filter, action)
}

var mainRouter = new Router()
var route = mainRouter.m.bind(mainRouter)

/**
 * Create a sub router
 * @returns {function} the method of a new Router object
 */
route.create = function() {
  var newSubRouter = new Router()
  return newSubRouter.m.bind(newSubRouter)
}

/**
 * Set the base of url
 * @param {(str|RegExp)} arg - a new base or '#' or '#!'
 */
route.base = function(arg) {
  base = arg || '#'
  current = getPathFromBase() // recalculate current path
}

/** Exec routing right now **/
route.exec = function() {
  emit(true)
}

/**
 * Replace the default router to yours
 * @param {function} fn - your parser function
 * @param {function} fn2 - your secondParser function
 */
route.parser = function(fn, fn2) {
  if (fn) parser = fn
  if (fn2) secondParser = fn2
}

/**
 * Helper function to get url query as an object
 * @returns {object} parsed query
 */
route.query = function() {
  var q = {}
  loc.href[REPLACE](/[?&](.+?)=([^&]*)/g, function(_, k, v) { q[k] = v })
  return q
}

/** Stop routing **/
route.stop = function () {
  if (started) {
    win[REMOVE_EVENT_LISTENER](POPSTATE, emit)
    doc[REMOVE_EVENT_LISTENER](clickEvent, click)
    central[TRIGGER]('stop')
    started = false
  }
}

/** Start routing **/
route.start = function () {
  if (!started) {
    win[ADD_EVENT_LISTENER](POPSTATE, emit)
    doc[ADD_EVENT_LISTENER](clickEvent, click)
    started = true
  }
}

/** Autostart the router **/
route.base()
route.start()

module.exports = route
<|endoftext|>


<commit_before>var spawn = require('child_process').spawn;

function sshClient(address,username,password){
    var self=this;
    this.address=address;
    this.user=username;
    this.line=0;
    this.buffer=null;
    this.exec=function(cmd) {
        if (this.connected) return;
        this.ssh = spawn('expect', [__dirname+'/login.exp',this.address,this.user,password,"-o ConnectTimeout=10",cmd]);
        setupEvents(this)
    }
    this.connect=function(connect) {
        //console.log('Connecting');
        if (this.connected) return;
        this.ssh = spawn('expect', [__dirname+'/login.exp',this.address,this.user,password,"-to ConnectTimeout=10"]);
        setupEvents(this)
        this.c=connect;
    }
    this.pipe=function(target) {
        this.ssh.stdout.pipe(target);
    }
    function setupEvents(self) {
        self.ssh.stdout.on('data', function (data) {
            //console.log("in:"+data.toString());
            if (self.connected) {
                return self.emit('data',data);
            }
            if (data.toString().match("logged")) {
                self.connected=true;
                self.c(self.address);
                return self.emit('data',data);
            }
            var str = data.toString().substr(0,16);
            if(str == "Connection refuse"){
                self.emit('refused',self.address);
                self.ssh.kill();
                return;
            }
            if(str == "Permission denied"){
                self.emit('denied',self.address);
                self.ssh.kill();
                return;
            }
        });

        self.ssh.on("exit",function(){
            self.connected=false;
            self.removeAllListeners('data');
            self.ssh.stdout.removeAllListeners('data');
            self.ssh.removeAllListeners();
            self.emit('close',self.address);
        });
    }

    this.write=function(data){
        //console.log("out:"+data.toString());
        this.ssh.stdin.write(data);
    }
    this.close=function(){
        this.ssh.kill();
    }
}
require('util').inherits(sshClient,require('events').EventEmitter);
module.exports=sshClient;
<commit_msg>Fix exec() bug<commit_after>var spawn = require('child_process').spawn;

function sshClient(address,username,password){
    var self=this;
    this.address=address;
    this.user=username;
    this.line=0;
    this.buffer=null;
    this.exec=function(cmd) {
        if (this.connected) return;
        this.ssh = spawn('expect', [__dirname+'/login.exp',this.address,this.user,password,"-o ConnectTimeout=10",cmd]);
        setupEvents(this)
    }
    this.connect=function(connect) {
        //console.log('Connecting');
        if (this.connected) return;
        this.ssh = spawn('expect', [__dirname+'/login.exp',this.address,this.user,password,"-to ConnectTimeout=10"]);
        setupEvents(this)
        this.c=connect;
    }
    this.pipe=function(target) {
        this.ssh.stdout.pipe(target);
    }
    function setupEvents(self) {
        self.ssh.stdout.on('data', function (data) {
            //console.log("in:"+data.toString());
            if (self.connected) {
                return self.emit('data',data);
            }
            if (data.toString().match("logged")) {
                self.connected=true;
                self.emit('connected',self.address);
                return self.emit('data',data);
            }
            var str = data.toString().substr(0,16);
            if(str == "Connection refuse"){
                self.emit('refused',self.address);
                self.ssh.kill();
                return;
            }
            if(str == "Permission denied"){
                self.emit('denied',self.address);
                self.ssh.kill();
                return;
            }
        });

        self.ssh.on("exit",function(){
            self.connected=false;
            self.removeAllListeners('data');
            self.ssh.stdout.removeAllListeners('data');
            self.ssh.removeAllListeners();
            self.emit('close',self.address);
        });
    }

    this.write=function(data){
        //console.log("out:"+data.toString());
        this.ssh.stdin.write(data);
    }
    this.close=function(){
        this.ssh.kill();
    }
}
require('util').inherits(sshClient,require('events').EventEmitter);
module.exports=sshClient;
<|endoftext|>