<commit_before>'use strict';

var util = require('util'),
	path = require('path'),
	fs = require('fs'),
	EventEmitter = require('events').EventEmitter;

var request = require('request'),
	async = require('async'),
	_ = require('lodash');

/**
 * constructor of Crawler
 */
function Crawler(opts) {
	this._init(opts);
}

util.inherits(Crawler, EventEmitter);

/**
 * initialize Crawler
 */
Crawler.prototype._init = function _init(opts) {
	var self = this;

	self._tasks = [];
	self._rules = {};
	self._taskCache = '';

	self.taskCounter = 0;
	self.failCounter = 0;
	self.settings = {
		interval: 0,
		retry: 3,
		concurrency: 1,
		skipRepetitiveTask: true,
		downloadDir: path.dirname(__dirname)
	};
	self.requestOpts = {
		timeout: 10000
	};
	self.errLog = '';

	self.twist(opts);

	// register listening 'pollTask'
	self.on('pollTask', function () {
		var size = self.settings.concurrency;
		size = size <= self._tasks.length ? size : self._tasks.length;
		if (self.q.length() < size) {
			var idle = size - self.q.length();
			var ts = self._tasks.splice(0, idle);
			while (idle != 0) {
				self.q.push(ts[ts.length - idle], function (err) {
					if (err) {
						return console.error(err);
					}
					if (self._tasks.length > 0) {
						self.emit('pollTask');
					}
				});
				idle--;
			}
		}
	});

	// processing of task pool
	self.q = async.queue(function (task, done) {
		var crawl = function crawl() {
			// cache task
			if (self.settings.skipRepetitiveTask) {
				self._taskCache = self._taskCache.concat(task.url + '|');
			}

			// log current
			console.log(util.format('Current No.%s: %s', self.taskCounter + 1, task.url));

			// call _crawl
			self._crawl(task, function (result) {
				// match rule
				var flag = false;
				Object.keys(self._rules).forEach(function (rule) {
					if (flag) {
						return;
					}
					if (new RegExp(rule).test(result.task.url)) {
						try {
							self._rules[rule](result);
						} catch (err) {
							self.errLog = self.errLog.concat(util.format('[Processing Error][No.%s]%s\n[%s]\n',
								result.task.id, result.task.url, err));
						} finally {
							flag = true;
							done();
						}
					}
				});
				// no matched
				if (!flag) {
					if (Object.keys(self._rules).length != 0) {
						self.errLog = self.errLog.concat(util.format('[No Rule Matched][No.%s]%s\n', result.task.id, result.task.url));
					}
					done();
				}
			});
		};

		// deferred execution for crawl's interval
		if (self.settings.interval != 0 && self.taskCounter != 0) {
			console.log('Crawler is sleeping...');
			setTimeout(crawl, self.settings.interval);
		} else {
			crawl();
		}
	}, self.settings.concurrency);

	self.q.drain = function () {
		console.log(util.format('[Crawler Finished] Total: %s.Success: %s.Fail: %s.',
			self.taskCounter, self.taskCounter - self.failCounter, self.failCounter));
		if (self.errLog.length > 0) {
			console.log(self.errLog);
		}
		if (self.onTaskPoolDrain) {
			self.onTaskPoolDrain();
		}
	};
};

/**
 * twist crawler's settings
 * @param <object> setting
 */
Crawler.prototype.twist = function twist(opts) {
	var self = this;
	if (opts) {
		if (opts.requestOpts) {
			self.requestOpts = _.assign(self.requestOpts, opts.requestOpts);
			delete opts.requestOpts;
		}
		self.settings = _.assign(self.settings, opts);
	}
	return self;
}

/**
 * add tasks to task pool
 * @param <array[string]> urls : array of url
 */
Crawler.prototype.addTasks = function addTasks(taskUrls, props) {
	var self = this;
	var taskProps = props ? props : {};
	if (Array.isArray(taskUrls)) {
		taskUrls = _.uniq(taskUrls);
		if (self.settings.skipRepetitiveTask) {
			taskUrls = taskUrls.filter(function (url) {
				return !new RegExp(url).test(self._taskCache);
			});
		}
		for (var i in taskUrls) {
			self._tasks.push(_.assign({ url: taskUrls[i] }, taskProps));
		}
	} else if (typeof (taskUrls) == 'string') {
		if (self.settings.skipRepetitiveTask && new RegExp(taskUrls).test(self._taskCache)) {
			return self;
		}
		self._tasks.push(_.assign({ url: taskUrls }, taskProps));
	}
	return self;
}

/**
 * add crawl's rule
 * @param <string> reg : reg string
 * @param <function> func : processing Data
 */
Crawler.prototype.addRule = function addRule(reg, func) {
	if (typeof (reg) == 'string') {
		reg = reg.replace(/\./g, '\\.').replace(/\*\*/g, '.*');
		this._rules[reg] = func;
	} else {
		this._rules['.*'] = reg;
	}
	return this;
}

/**
 * fetch/crawl a single page for task
 * @param <string> url : url of crawling page
 * @param <function> callback
 */
Crawler.prototype._crawl = function _crawl(task, callback) {
	var self = this;

	var opts = _.assign(self.requestOpts, { url: task.url });
	if (opts.proxy == '') {
		delete opts.proxy;
	}
	if (task.requestOpts) {
		opts = _.assign(opts, task.requestOpts);
	}

	task.retry = 0;
	task.id = ++self.taskCounter;

	// log error info
	var logError = function logError(info) {
		console.log(util.format('[Retry][%s][%s] : %s', info, ++task.retry, task.url));
		if (task.retry == self.settings.retry) {
			self.failCounter++;
			self.errLog = self.errLog.concat(util.format('[Retry Failed][No.%s][%s]%s\n', task.id, info, task.url));
		}
	}

	// normal task: crawling html
	var normal = function normal(cb) {
		request(opts, function (e, r, body) {
			if (!e && r.statusCode == 200) {
				cb(null, { task: task, body: body });
			} else {
				var info = e ? e.code : r.statusCode;
				logError(info);
				cb(info);
			}
		});
	};

	// download task
	var download = function download(cb) {
		var file = task.downloadFile ? task.downloadFile : path.basename(task.url);
		file = path.resolve(self.settings.downloadDir, file);

		// insure file's dir exists
		var f = true;
		var fileDir = path.dirname(file);
		var vFile = fileDir;
		while(f) {
			try {
				fs.mkdirSync(vFile);
				vFile = fileDir;
			} catch (err) {
				if (err.code == 'EEXIST') {
					if (vFile == fileDir) {
						f = false;
					}
				} else if (err.code == 'ENOENT') {
					vFile = path.dirname(vFile);
				} else {
					f = false;
					logError(err);
					cb(err);
				}
			}
		}

		// download the file
		var req = request(opts).pipe(fs.createWriteStream(file));
		req.on('finish', function (e) {
			if (e) {
				logError(e);
				cb(e);
			} else {
				cb(null, { task: task, body: 'This is a download task.' });
			}
		});
	};

	var func = task.downloadTask == true ? download : normal;

	async.retry({
		times: self.settings.retry,
		interval: self.settings.interval
	}, func, function (e, result) {
		if (e) {
			callback({ task: task });
		} else {
			callback(result);
		}
	});
}

/**
 * start the Crawler
 * @param <function> callback
 */
Crawler.prototype.start = function start(callback) {
	var self = this;

	if (self._tasks.length == 0) {
		console.error('Task pool has nothing!');
		if (callback) {
			return callback();
		}
		return;
	}

	if (callback) {
		self.onTaskPoolDrain = callback;
	}

	console.log('[Crawler Started]');

	self.emit('pollTask');
}

module.exports = Crawler;
<commit_msg>Update annotations.<commit_after>'use strict';

var util = require('util'),
	path = require('path'),
	fs = require('fs'),
	EventEmitter = require('events').EventEmitter;

var request = require('request'),
	async = require('async'),
	_ = require('lodash');

/**
 * constructor of Crawler
 */
function Crawler(opts) {
	this._init(opts);
}

// inherits from EventEmitter
util.inherits(Crawler, EventEmitter);

/**
 * initialize Crawler
 */
Crawler.prototype._init = function _init(opts) {
	var self = this;

	// private props
	self._tasks = [];
	self._rules = {};
	self._taskCache = '';

	// public props
	self.taskCounter = 0;
	self.failCounter = 0;
	self.settings = {
		interval: 0,
		retry: 3,
		concurrency: 1,
		skipRepetitiveTask: true,
		downloadDir: path.dirname(__dirname)
	};
	// options of task request
	self.requestOpts = {
		timeout: 10000
	};
	self.errLog = '';

	self.twist(opts);

	// register listening 'pollTask', push tasks into task-pool
	self.on('pollTask', function () {
		var size = self.settings.concurrency;
		size = size <= self._tasks.length ? size : self._tasks.length;
		if (self.q.length() < size) {
			var idle = size - self.q.length();
			var ts = self._tasks.splice(0, idle);
			while (idle != 0) {
				self.q.push(ts[ts.length - idle], function (err) {
					if (err) {
						return console.error(err);
					}
					if (self._tasks.length > 0) {
						self.emit('pollTask');
					}
				});
				idle--;
			}
		}
	});

	// processing of task pool
	self.q = async.queue(function (task, done) {
		var crawl = function crawl() {
			// cache task
			if (self.settings.skipRepetitiveTask) {
				self._taskCache = self._taskCache.concat(task.url + '|');
			}

			// log current
			console.log(util.format('Current No.%s: %s', self.taskCounter + 1, task.url));

			// call _crawl
			self._crawl(task, function (result) {
				// match rule
				var flag = false;
				Object.keys(self._rules).forEach(function (rule) {
					if (flag) {
						return;
					}
					if (new RegExp(rule).test(result.task.url)) {
						try {
							self._rules[rule](result);
						} catch (err) {
							self.errLog = self.errLog.concat(util.format('[Processing Error][No.%s]%s\n[%s]\n',
								result.task.id, result.task.url, err));
						} finally {
							flag = true;
							done();
						}
					}
				});
				// no matched
				if (!flag) {
					if (Object.keys(self._rules).length != 0) {
						self.errLog = self.errLog.concat(util.format('[No Rule Matched][No.%s]%s\n', result.task.id, result.task.url));
					}
					done();
				}
			});
		};

		// deferred execution for crawl's interval
		if (self.settings.interval != 0 && self.taskCounter != 0) {
			console.log('Crawler is sleeping...');
			setTimeout(crawl, self.settings.interval);
		} else {
			crawl();
		}
	}, self.settings.concurrency);

	// task-pool is drained
	self.q.drain = function () {
		console.log(util.format('[Crawler Finished] Total: %s.Success: %s.Fail: %s.',
			self.taskCounter, self.taskCounter - self.failCounter, self.failCounter));
		if (self.errLog.length > 0) {
			console.log(self.errLog);
		}
		if (self.onTaskPoolDrain) {
			self.onTaskPoolDrain();
		}
	};
};

/**
 * twist crawler's settings
 * @param <object> setting
 */
Crawler.prototype.twist = function twist(opts) {
	var self = this;
	if (opts) {
		if (opts.requestOpts) {
			self.requestOpts = _.assign(self.requestOpts, opts.requestOpts);
			delete opts.requestOpts;
		}
		self.settings = _.assign(self.settings, opts);
	}
	return self;
}

/**
 * add tasks to task pool
 * @param <string || array[string]> urls
 * @param <object> props : properties of task
 */
Crawler.prototype.addTasks = function addTasks(taskUrls, props) {
	var self = this;
	var taskProps = props ? props : {};
	if (Array.isArray(taskUrls)) {
		taskUrls = _.uniq(taskUrls);
		if (self.settings.skipRepetitiveTask) {
			taskUrls = taskUrls.filter(function (url) {
				return !new RegExp(url).test(self._taskCache);
			});
		}
		for (var i in taskUrls) {
			self._tasks.push(_.assign({ url: taskUrls[i] }, taskProps));
		}
	} else if (typeof (taskUrls) == 'string') {
		if (self.settings.skipRepetitiveTask && new RegExp(taskUrls).test(self._taskCache)) {
			return self;
		}
		self._tasks.push(_.assign({ url: taskUrls }, taskProps));
	}
	return self;
}

/**
 * add crawl's rule
 * @param <string> reg : reg string
 * @param <function> func : processing Data
 */
Crawler.prototype.addRule = function addRule(reg, func) {
	if (typeof (reg) == 'string') {
		reg = reg.replace(/\./g, '\\.').replace(/\*\*/g, '.*');
		this._rules[reg] = func;
	} else {
		this._rules['.*'] = reg;
	}
	return this;
}

/**
 * fetch/crawl a page for the task
 * @param <object> task
 * @param <function> callback
 */
Crawler.prototype._crawl = function _crawl(task, callback) {
	var self = this;

	// init options of the request
	var opts = _.assign(self.requestOpts, { url: task.url });
	if (opts.proxy == '') {
		delete opts.proxy;
	}
	if (task.requestOpts) {
		opts = _.assign(opts, task.requestOpts);
	}

	// retry times
	task.retry = 0;
	task.id = ++self.taskCounter;

	// log error info
	var logError = function logError(info) {
		console.log(util.format('[Retry][%s][%s] : %s', info, ++task.retry, task.url));
		if (task.retry == self.settings.retry) {
			self.failCounter++;
			self.errLog = self.errLog.concat(util.format('[Retry Failed][No.%s][%s]%s\n', task.id, info, task.url));
		}
	}

	// normal task: crawling html
	var normal = function normal(cb) {
		request(opts, function (e, r, body) {
			if (!e && r.statusCode == 200) {
				cb(null, { task: task, body: body });
			} else {
				var info = e ? e.code : r.statusCode;
				logError(info);
				cb(info);
			}
		});
	};

	// download task
	var download = function download(cb) {
		var file = task.downloadFile ? task.downloadFile : path.basename(task.url);
		file = path.resolve(self.settings.downloadDir, file);

		// insure file's dir exists
		var f = true;
		var fileDir = path.dirname(file);
		var vFile = fileDir;
		while(f) {
			try {
				fs.mkdirSync(vFile);
				vFile = fileDir;
			} catch (err) {
				if (err.code == 'EEXIST') {
					if (vFile == fileDir) {
						f = false;
					}
				} else if (err.code == 'ENOENT') {
					vFile = path.dirname(vFile);
				} else {
					f = false;
					logError(err);
					cb(err);
				}
			}
		}

		// download the file
		var req = request(opts).pipe(fs.createWriteStream(file));
		req.on('finish', function (e) {
			if (e) {
				logError(e);
				cb(e);
			} else {
				cb(null, { task: task, body: 'This is a download task.' });
			}
		});
	};

	// download task or not
	var func = task.downloadTask == true ? download : normal;

	// retry this task if errors occured
	async.retry({
		times: self.settings.retry,
		interval: self.settings.interval
	}, func, function (e, result) {
		if (e) {
			callback({ task: task });
		} else {
			callback(result);
		}
	});
}

/**
 * start the Crawler
 * @param <function> callback
 */
Crawler.prototype.start = function start(callback) {
	var self = this;

	// empty task-pool
	if (self._tasks.length == 0) {
		console.error('Task pool has nothing!');
		if (callback) {
			return callback();
		}
		return;
	}

	if (callback) {
		self.onTaskPoolDrain = callback;
	}

	console.log('[Crawler Started]');

	// start task-pool
	self.emit('pollTask');
}

module.exports = Crawler;
<|endoftext|>


<commit_before>import CustomError from 'customerror';
import Collection from './Collection';

class QueryCompiler {

  /**
   * Constructs a new QueryCompiler instance for the designated collection.
   * @param {string} collection the collection to compile queries for.
   * @constructor
   */
  constructor(collection: string) {
    this.collection = collection;
  }

  /**
   * Compiles and returns a selection clause, based on the supplied AST.
   * @param {Array} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileSelection(ast: Array) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a projection clause, based on the supplied AST.
   * @param {Array} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileProjection(ast: Array) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns an orderby clause, based on the supplied AST.
   * @param {Array} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileOrderBy(ast: Array) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a new "find" query, based on the supplied AST.
   * @param {Object} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileFind(ast: Object) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a new "count" query, based on the supplied AST.
   * @param {Object} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileCount(ast: Object) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a new "remove" query, based on the supplied AST.
   * @param {Object} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileRemove(ast: Object) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a new "insert" query, based on the supplied AST.
   * @param {Object} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileInsert(ast: Object) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a new "update" query, based on the supplied AST.
   * @param {Object} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileUpdate(ast: Object) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

}

export default QueryCompiler;
<commit_msg>Refactor the QueryCompiler methods<commit_after>import _ from 'lodash';
import type from 'type-of';
import CustomError from 'customerror';

class QueryCompiler {

  /**
   * Constructs a new QueryCompiler instance for the designated collection.
   * @param {string} collectionName the name of the collection.
   * @param {Array<string>} attributes the attributes (a.k.a. columns or fields) of the collection.
   * @constructor
   */
  constructor(collectionName: string, attributes: Array<string>) {
    this.collectionName = collectionName;
    this.attributes = attributes;
  }

  /**
   * Compiles and returns a selection expression, based on the supplied AST.
   * @param {Array} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileSelectionExpression(ast: Array) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a projection expression, based on the supplied AST.
   * @param {Array} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileProjectionExpression(ast: Array) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns an orderby expression, based on the supplied AST.
   * @param {Array} ast abstract syntax tree.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileOrderByExpression(ast: Array) {
    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a "find" query, based on the supplied properties.
   * @param {Object} props query properties.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileFindQuery(props: Object) {
    if (!_.isPlainObject(props)) {
      throw new TypeError(`Invalid props argument; expected object, received ${type(props)}`);
    }

    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a "count" query, based on the supplied properties.
   * @param {Object} props query properties.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileCountQuery(props: Object) {
    if (!_.isPlainObject(props)) {
      throw new TypeError(`Invalid props argument; expected object, received ${type(props)}`);
    }

    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns a "remove" query, based on the supplied properties.
   * @param {Object} props query properties.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileRemoveQuery(props: Object) {
    if (!_.isPlainObject(props)) {
      throw new TypeError(`Invalid props argument; expected object, received ${type(props)}`);
    }

    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns an "insert" query, based on the supplied properties.
   * @param {Object} props query properties.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileInsertQuery(props: Object) {
    if (!_.isPlainObject(props)) {
      throw new TypeError(`Invalid props argument; expected object, received ${type(props)}`);
    }

    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns an "upsert" query, based on the supplied properties.
   * @param {Object} props query properties.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileUpsertQuery(props: Object) {
    if (!_.isPlainObject(props)) {
      throw new TypeError(`Invalid props argument; expected object, received ${type(props)}`);
    }

    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

  /**
   * Compiles and returns an "update" query, based on the supplied properties.
   * @param {Object} props query properties.
   * @return {Object}
   * @throws {NotImplementedException} if method has not been implemented or does not apply to the current database engine.
   */
  compileUpdateQuery(props: Object) {
    if (!_.isPlainObject(props)) {
      throw new TypeError(`Invalid props argument; expected object, received ${type(props)}`);
    }

    throw new CustomError('Method not implemented', 'NotImplementedException');
  }

}

export default QueryCompiler;
<|endoftext|>


<commit_before>const mongoose = require('mongoose');
const Promise = mongoose.Promise = require('bluebird');
const bcrypt = require('bcrypt');
const eachAsync = require('each-async');
const db = require('./common');

const User = mongoose.models.User;
const Team = mongoose.models.Team;
const UserTeam = mongoose.models.UserTeam;

const dbUser = require('./User');
const dbTeam = require('./Team');

const exp = {};

module.exports = exp;

exp.testSeed = async function() {
    if (process.env.ENV != 'dev'){
        console.log("Not DEV environment - skipping seed");
        return;
    }
    const data = {};
    await db.deleteAll();
    await exp.testSeedTeams(data);
    await exp.testSeedUsers(data);
    await exp.testSeedTeamsCoaches(data);
    await exp.testSeedMembers(data);
    console.log('==== TESTING');
    let myId = '00000000010000000002000'+'0';
    let teamId = '00000000010000000002000'+'0';
    let coachId = '00000000010000000002000'+'1';

    console.log("===== TEAM DETAILS START");
    let t = await dbTeam.getTeamDetails(myId, teamId);
    console.log("===== TEAM DETAILS RESULT");
    console.log(t);

    console.log("===== TEAM COACHES START");
    let tc = await dbTeam.getTeamCoaches(myId, teamId);
    console.log("===== TEAM COACHES RESULT");
    console.log(tc);

    console.log("===== TEAM MEMBERS START");
    let tm = await dbTeam.getTeamMembers(myId, teamId);
    console.log("===== TEAM MEMBERS RESULT");
    console.log(tm);

};

exp.testSeedTeams = function(data){
    return new Promise(function (fulfill, reject) {
        if (!data) data = {};
        data.teams = [];
        console.log("Seeding teams");
        eachAsync(
            ['team1', 'team2', 'team3', 'team4', 'team5'],
            async function (item, index, done) {
                try {
                    const team = await Team.create({name: item, _id:'00000000010000000002000'+index});
                    console.log("Team created: " + team.name + "===" + team.id);
                    data.teams.push({id: team.id, name: team.name});
                    return done();
                } catch (err) {
                    reject(err);
                }
            },
            function (err) {
                if (err) reject(err);
                console.log("Finished teams");
                fulfill(data);
            })
    });

};

exp.testSeedUsers = async function(data){
    return new Promise(function (fulfill, reject){
        if (!data) data = {};
        data.users = [];
        eachAsync(
            [
                ['user1','pwd1'],
                ['user2','pwd2'],
                ['user3','pwd3'],
                ['user4','pwd4'],
                ['user5','pwd5']
            ],
            async function (item, index, done) {
                const s = await bcrypt.genSalt(1);
                const h = await bcrypt.hash(item[1],s);
                const user = await User.create(
                    {
                        _id:'00000000010000000002000'+index,
                        username: item[0],
                        passwordHash: h,
                        salt:s,
                        fullName: 'Full '+item[0],
                        email: item[0]+'@email'
                    });
                console.log("User created: " + user.username + "===" + user.id);
                data.users.push({id: user.id, username: user.username});
                return done();
            },
            function (err) {
                if (err) reject(err);
                console.log("Finished users");
                fulfill(data);
            })

    })
};

exp.testSeedTeamsCoaches = async function(data) {
    return new Promise(function (fulfill, reject) {
        if (!data) data = {};
        console.log("Assigning coaches");
        eachAsync(
            data.teams,
            async function (item, index, done) {
                const ut = await UserTeam.create(
                    {
                        teamId: item.id,
                        userId: data.users[index%data.users.length].id,
                        role: 'coach'
                    }
                );
                console.log("Coach for team",item.name,' is ',data.users[index%data.users.length].username);
                return done();
            },
            function (err){
                if (err) reject(err);
                console.log("Finished coaches")
                fulfill(data)
            }
        )

    });
};

exp.testSeedMembers = async function(data){
    return new Promise(
        function (fulfill, reject) {
            console.log('Seeding members');
            if (!data) data = {};
            eachAsync(
                data.teams,
                async function (item, index, done) {
                    for (u of [1, 2, 3, 4, 5, 6]) {
                        let uId = '2'+index+'000000010000000002000' + u;
                        let uName = 'user' + u + '-' + item.name;
                        const user = await User.create(
                            {
                                _id: uId,
                                fullName: 'Full '+uName
                            });
                        await UserTeam.create(
                            {
                                userId: uId,
                                teamId: item.id,
                                role: 'member'
                            }
                        );
                        console.log('Member ', uName, ' team ', item.name);

                    }

                    console.log("Members assigned to team: ", item.name);
                    return done();
                },
                function (err) {
                    if (err) reject(err);
                    console.log("Finished assigning team members");
                    fulfill(data);
                }
            )

        }
    )
};
<commit_msg>team test data seed enhancement<commit_after>const mongoose = require('mongoose');
const Promise = mongoose.Promise = require('bluebird');
const bcrypt = require('bcrypt');
const eachAsync = require('each-async');
const db = require('./common');

const User = mongoose.models.User;
const Team = mongoose.models.Team;
const UserTeam = mongoose.models.UserTeam;

const dbUser = require('./User');
const dbTeam = require('./Team');

const exp = {};

module.exports = exp;

exp.testSeed = async function() {
    if (process.env.ENV != 'dev'){
        console.log("Not DEV environment - skipping seed");
        return;
    }
    const data = {};
    await db.deleteAll();
    await exp.testSeedTeams(data);
    await exp.testSeedUsers(data);
    await exp.testSeedTeamsCoaches(data);
    await exp.testSeedMembers(data);
    console.log('==== TESTING');
    let myId = '00000000010000000002000'+'0';
    let teamId = '00000000010000000002000'+'0';
    let coachId = '00000000010000000002000'+'1';

    console.log("===== TEAM DETAILS START");
    let t = await dbTeam.getTeamDetails(myId, teamId);
    console.log("===== TEAM DETAILS RESULT");
    console.log(t);

    console.log("===== TEAM COACHES START");
    let tc = await dbTeam.getTeamCoaches(myId, teamId);
    console.log("===== TEAM COACHES RESULT");
    console.log(tc);

    console.log("===== TEAM MEMBERS START");
    let tm = await dbTeam.getTeamMembers(myId, teamId);
    console.log("===== TEAM MEMBERS RESULT");
    console.log(tm);

};

exp.testSeedTeams = function(data){
    return new Promise(function (fulfill, reject) {
        if (!data) data = {};
        data.teams = [];
        console.log("Seeding teams");
        eachAsync(
            [
                Team.testData({},'1'),
                Team.testData({},'2'),
                Team.testData({},'3'),
                Team.testData({},'4'),
                Team.testData({},'5')
            ],
            async function (item, index, done) {
                try {
                    const team = await Team.create(Object.assign(item, {_id:'00000000010000000002000'+index}));
                    console.log("Team created: " + team.name + "===" + team.id);
                    data.teams.push({id: team.id, name: team.name});
                    return done();
                } catch (err) {
                    reject(err);
                }
            },
            function (err) {
                if (err) reject(err);
                console.log("Finished teams");
                fulfill(data);
            })
    });

};

exp.testSeedUsers = async function(data){
    return new Promise(function (fulfill, reject){
        if (!data) data = {};
        data.users = [];
        eachAsync(
            [
                ['user1','pwd1'],
                ['user2','pwd2'],
                ['user3','pwd3'],
                ['user4','pwd4'],
                ['user5','pwd5']
            ],
            async function (item, index, done) {
                const s = await bcrypt.genSalt(1);
                const h = await bcrypt.hash(item[1],s);
                const user = await User.create(
                    {
                        _id:'00000000010000000002000'+index,
                        username: item[0],
                        passwordHash: h,
                        salt:s,
                        fullName: 'Full '+item[0],
                        email: item[0]+'@email'
                    });
                console.log("User created: " + user.username + "===" + user.id);
                data.users.push({id: user.id, username: user.username});
                return done();
            },
            function (err) {
                if (err) reject(err);
                console.log("Finished users");
                fulfill(data);
            })

    })
};

exp.testSeedTeamsCoaches = async function(data) {
    return new Promise(function (fulfill, reject) {
        if (!data) data = {};
        console.log("Assigning coaches");
        eachAsync(
            data.teams,
            async function (item, index, done) {
                const ut = await UserTeam.create(
                    {
                        teamId: item.id,
                        userId: data.users[index%data.users.length].id,
                        role: 'coach'
                    }
                );
                console.log("Coach for team",item.name,' is ',data.users[index%data.users.length].username);
                return done();
            },
            function (err){
                if (err) reject(err);
                console.log("Finished coaches")
                fulfill(data)
            }
        )

    });
};

exp.testSeedMembers = async function(data){
    return new Promise(
        function (fulfill, reject) {
            console.log('Seeding members');
            if (!data) data = {};
            eachAsync(
                data.teams,
                async function (item, index, done) {
                    for (u of [1, 2, 3, 4, 5, 6]) {
                        let uId = '2'+index+'000000010000000002000' + u;
                        let uName = 'user' + u + '-' + item.name;
                        const user = await User.create(
                            {
                                _id: uId,
                                fullName: 'Full '+uName
                            });
                        await UserTeam.create(
                            {
                                userId: uId,
                                teamId: item.id,
                                role: 'member'
                            }
                        );
                        console.log('Member ', uName, ' team ', item.name);

                    }

                    console.log("Members assigned to team: ", item.name);
                    return done();
                },
                function (err) {
                    if (err) reject(err);
                    console.log("Finished assigning team members");
                    fulfill(data);
                }
            )

        }
    )
};
<|endoftext|>


<commit_before>"use strict";

var debug = require('debug')('waigo-cli-init'),
  path = require('path'),
  util = require('util');

var waigo = require('../../'),
  AbstractCommand = waigo.load('support/cliCommand');

var dataFolder = path.join(__dirname, 'data', 'init');

/**
 * The init CLI command.
 *
 * This command initialises a skeleton Waigo application with a basic view template.
 */
var Command = module.exports = function() {
  AbstractCommand.call(this,
    'Initialise and create a skeleton Waigo app and build tools', []
  );
};
util.inherits(Command, AbstractCommand);

/**
 * Run this command.
 */
Command.prototype.run = function*() {
  yield this.installPkgs(['waigo']);

  yield this.installPkgs([
    'coffee-script',
    'gulp@3.8.x',
    'gulp-if@1.2.x',
    'gulp-autoprefixer@2.1.x',
    'gulp-minify-css@0.4.x',
    'gulp-concat@2.4.x',
    'gulp-stylus@2.0.x',
    'nib',
    'rupture',
    'gulp-uglify@1.1.x',
    'gulp-util@3.0.x',
    'gulp-nodemon@1.0.x',
    'yargs'
  ], {
    dev: true,
  });

  yield this.copyFile(path.join(dataFolder, 'start-app.js'), 'start-app.js');
  yield this.copyFile(path.join(dataFolder, 'README.md'), 'src/README.md');
  yield this.copyFile(path.join(dataFolder, '.gitignore'), '.gitignore');

  yield this.copyFile(path.join(waigo.getWaigoFolder(), 'config', 'base.js'), 'src/config/base.js');

  yield this.copyFile(path.join(dataFolder, 'gulpfile.coffee'), 'gulpfile.coffee');
  yield this.copyFolder(path.join(dataFolder, 'gulp'), 'gulp');
};

<commit_msg>install semver pkg for skeleton apps<commit_after>"use strict";

var debug = require('debug')('waigo-cli-init'),
  path = require('path'),
  util = require('util');

var waigo = require('../../'),
  AbstractCommand = waigo.load('support/cliCommand');

var dataFolder = path.join(__dirname, 'data', 'init');

/**
 * The init CLI command.
 *
 * This command initialises a skeleton Waigo application with a basic view template.
 */
var Command = module.exports = function() {
  AbstractCommand.call(this,
    'Initialise and create a skeleton Waigo app and build tools', []
  );
};
util.inherits(Command, AbstractCommand);

/**
 * Run this command.
 */
Command.prototype.run = function*() {
  yield this.installPkgs(['waigo']);

  yield this.installPkgs([
    'semver',
    'coffee-script',
    'gulp@3.8.x',
    'gulp-if@1.2.x',
    'gulp-autoprefixer@2.1.x',
    'gulp-minify-css@0.4.x',
    'gulp-concat@2.4.x',
    'gulp-stylus@2.0.x',
    'nib',
    'rupture',
    'gulp-uglify@1.1.x',
    'gulp-util@3.0.x',
    'gulp-nodemon@1.0.x',
    'yargs'
  ], {
    dev: true,
  });

  yield this.copyFile(path.join(dataFolder, 'start-app.js'), 'start-app.js');
  yield this.copyFile(path.join(dataFolder, 'README.md'), 'src/README.md');
  yield this.copyFile(path.join(dataFolder, '.gitignore'), '.gitignore');

  yield this.copyFile(path.join(waigo.getWaigoFolder(), 'config', 'base.js'), 'src/config/base.js');

  yield this.copyFile(path.join(dataFolder, 'gulpfile.coffee'), 'gulpfile.coffee');
  yield this.copyFolder(path.join(dataFolder, 'gulp'), 'gulp');
};

<|endoftext|>


<commit_before>var Long = require('long');

var isSimpleType = {};
'ybnquigsoxtd'.split(' ').forEach(function(t) {
  isSimpleType[t] = true;
});

// Buffer + position + global start position ( used in alignment )
function DBusBuffer(buffer, startPos, options)
{
  if (typeof(options) !== 'object') options = { ayBuffer: true, ReturnLongjs: false }; // default settings object
  else if (options.ayBuffer == undefined) options.ayBuffer = true; // enforce truthy default props
  this.options = options;
  //this.options = Object.assign({ ayBuffer: true, ReturnLongjs: false }, options); // or use 'object-assign' polyfill
  this.buffer = buffer;
  this.startPos = startPos ? startPos : 0,
  this.pos = 0;
}

DBusBuffer.prototype.align = function(power) {
  var allbits = (1<<power) - 1;
  var paddedOffset = ((this.pos + this.startPos + allbits) >> power) << power;
  this.pos = paddedOffset - this.startPos;
}

DBusBuffer.prototype.readInt8 = function() {
  this.pos++;
  return this.buffer[this.pos - 1];
}

DBusBuffer.prototype.readSInt16 = function() {
  this.align(1);
  var res = this.buffer.readInt16LE(this.pos);
  this.pos += 2;
  return res;
}

DBusBuffer.prototype.readInt16 = function() {
  this.align(1);
  var res = this.buffer.readUInt16LE(this.pos);
  this.pos += 2;
  return res;
}

DBusBuffer.prototype.readSInt32 = function() {
  this.align(2);
  var res = this.buffer.readInt32LE(this.pos);
  this.pos += 4;
  return res;
}

DBusBuffer.prototype.readInt32 = function() {
  this.align(2);
  var res = this.buffer.readUInt32LE(this.pos);
  this.pos += 4;
  return res;
}

DBusBuffer.prototype.readDouble = function() {
  this.align(3);
  var res = this.buffer.readDoubleLE(this.pos);
  this.pos += 8;
  return res;
}

DBusBuffer.prototype.readString = function(len) {
  if (len === 0) {
    this.pos++;
    return '';
  }
  var res = this.buffer.toString('utf8', this.pos, this.pos + len);
  this.pos += len + 1; // dbus strings are always zero-terminated ('s' and 'g' types)
  return res;
}

var parseSignature = require('./signature.js');

DBusBuffer.prototype.readTree = function readTree(tree) {
  switch (tree.type) {
  case '(':
  case '{':
  case 'r':
    this.align(3);
    return this.readStruct(tree.child);
  case 'a':
    if (!tree.child || tree.child.length != 1)
      throw new Error('Incorrect array element signature');
    var arrayBlobLength = this.readInt32();
    return this.readArray(tree.child[0], arrayBlobLength);
    return arr;
    case 'v':
      return this.readVariant();
    default:
      return this.readSimpleType(tree.type);
  }
}

DBusBuffer.prototype.read = function read(signature) {
  var tree = parseSignature(signature);
  return this.readStruct(tree);
}

DBusBuffer.prototype.readVariant = function readVariant() {
  var signature = this.readSimpleType('g');
  //if (isSimpleType[signature])
  //  return this.readSimpleType(signature);

  //if (signature == 'a{sv}')
  //{
  //  var arrayBlobLength = this.readInt32();
  //  return this.readArray(parseSignature(signatur
  //}
  var tree = parseSignature(signature);
  return [tree, this.readStruct(tree)];
}

DBusBuffer.prototype.readStruct = function readStruct(struct) {
  var result = [];
  for (var i = 0; i < struct.length; ++i) {
    result.push(this.readTree(struct[i]));
  }
  return result;
}

// check if it's a{sX} s -> any type
// return value type
function isHash(t) {
  if (t.type == '{' && t.child[0].type == 's')
    return t.child[1];
  return null;
}

DBusBuffer.prototype.readArray = function readArray(eleType, arrayBlobSize) {
  var result;
  var key, value;
  var start = this.pos;

  /*
  if (isHash(eleType)) {
    result = {};
    while(this.pos < start + arrayBlobSize) {
      this.align(3);
      key = this.readTree(eleType.child[0]);
      result[key] = this.readTree(eleType.child[1]);
    }
    console.log('Hash!!!', eleType, parseSignature.fromTree(eleType), result);
    return result;
  }
  */

  // special case: treat ay as Buffer
  if (eleType.type === 'y' && this.options.ayBuffer) {
    this.pos += arrayBlobSize;
    return this.buffer.slice(start, this.pos);
  }

  // end of array is start of first element + array size
  // we need to add 4 bytes if not on 8-byte boundary
  // and array element needs 8 byte alignment
  if (['x', 't', 'd', '{', '(', 'r'].indexOf(eleType.type) != -1)
    this.align(3);
  var end = this.pos + arrayBlobSize;
  result = [];
  while(this.pos < end)
    result.push(this.readTree(eleType));
  return result;
}

DBusBuffer.prototype.readSimpleType = function readSimpleType(t) {
  switch (t) {
  case 'y':
    return this.readInt8();
  case 'b':
    // TODO: spec says that true is strictly 1 and false is strictly 0
    // shold we error (or warn?) when non 01 values?
    return this.readInt32() ? true : false;
  case 'n':
    return this.readSInt16();
  case 'q':
    return this.readInt16();
  case 'u':
    return this.readInt32();
  case 'i':
    return this.readSInt32();
  case 'g':
    var len = this.readInt8();
    return this.readString(len);
  case 's':
  case 'o':
    var len = this.readInt32();
    return this.readString(len);
    // TODO: validate object path here
    //if (t === 'o' && !isValidObjectPath(str))
    //  throw new Error('string is not a valid object path'));
  case 'x': //signed
    this.align(3);
    var word0 = this.readInt32();
    var word1 = this.readInt32();
    var data = Long.fromBits(word0, word1, false);
    if (this.options.ReturnLongjs) return data;
    return data.toNumber(); // convert to number (good up to 53 bits)
  case 't': //unsigned
    this.align(3);
    var word0 = this.readInt32();
    var word1 = this.readInt32();
    var data = Long.fromBits(word0, word1, true);
    if (this.options.ReturnLongjs) return data;
    return data.toNumber(); // convert to number (good up to 53 bits)
  case 'd':
    return this.readDouble();
  default:
    throw new Error('Unsupported type: ' + t);
  }
  return result;
}

module.exports = DBusBuffer;
<commit_msg>remove some unreachable code from dbuffer.js<commit_after>var Long = require('long');

var isSimpleType = {};
'ybnquigsoxtd'.split(' ').forEach(function(t) {
  isSimpleType[t] = true;
});

// Buffer + position + global start position ( used in alignment )
function DBusBuffer(buffer, startPos, options)
{
  if (typeof(options) !== 'object') options = { ayBuffer: true, ReturnLongjs: false }; // default settings object
  else if (options.ayBuffer == undefined) options.ayBuffer = true; // enforce truthy default props
  this.options = options;
  //this.options = Object.assign({ ayBuffer: true, ReturnLongjs: false }, options); // or use 'object-assign' polyfill
  this.buffer = buffer;
  this.startPos = startPos ? startPos : 0,
  this.pos = 0;
}

DBusBuffer.prototype.align = function(power) {
  var allbits = (1<<power) - 1;
  var paddedOffset = ((this.pos + this.startPos + allbits) >> power) << power;
  this.pos = paddedOffset - this.startPos;
}

DBusBuffer.prototype.readInt8 = function() {
  this.pos++;
  return this.buffer[this.pos - 1];
}

DBusBuffer.prototype.readSInt16 = function() {
  this.align(1);
  var res = this.buffer.readInt16LE(this.pos);
  this.pos += 2;
  return res;
}

DBusBuffer.prototype.readInt16 = function() {
  this.align(1);
  var res = this.buffer.readUInt16LE(this.pos);
  this.pos += 2;
  return res;
}

DBusBuffer.prototype.readSInt32 = function() {
  this.align(2);
  var res = this.buffer.readInt32LE(this.pos);
  this.pos += 4;
  return res;
}

DBusBuffer.prototype.readInt32 = function() {
  this.align(2);
  var res = this.buffer.readUInt32LE(this.pos);
  this.pos += 4;
  return res;
}

DBusBuffer.prototype.readDouble = function() {
  this.align(3);
  var res = this.buffer.readDoubleLE(this.pos);
  this.pos += 8;
  return res;
}

DBusBuffer.prototype.readString = function(len) {
  if (len === 0) {
    this.pos++;
    return '';
  }
  var res = this.buffer.toString('utf8', this.pos, this.pos + len);
  this.pos += len + 1; // dbus strings are always zero-terminated ('s' and 'g' types)
  return res;
}

var parseSignature = require('./signature.js');

DBusBuffer.prototype.readTree = function readTree(tree) {
  switch (tree.type) {
  case '(':
  case '{':
  case 'r':
    this.align(3);
    return this.readStruct(tree.child);
  case 'a':
    if (!tree.child || tree.child.length != 1)
      throw new Error('Incorrect array element signature');
    var arrayBlobLength = this.readInt32();
    return this.readArray(tree.child[0], arrayBlobLength);
    case 'v':
      return this.readVariant();
    default:
      return this.readSimpleType(tree.type);
  }
}

DBusBuffer.prototype.read = function read(signature) {
  var tree = parseSignature(signature);
  return this.readStruct(tree);
}

DBusBuffer.prototype.readVariant = function readVariant() {
  var signature = this.readSimpleType('g');
  //if (isSimpleType[signature])
  //  return this.readSimpleType(signature);

  //if (signature == 'a{sv}')
  //{
  //  var arrayBlobLength = this.readInt32();
  //  return this.readArray(parseSignature(signatur
  //}
  var tree = parseSignature(signature);
  return [tree, this.readStruct(tree)];
}

DBusBuffer.prototype.readStruct = function readStruct(struct) {
  var result = [];
  for (var i = 0; i < struct.length; ++i) {
    result.push(this.readTree(struct[i]));
  }
  return result;
}

// check if it's a{sX} s -> any type
// return value type
function isHash(t) {
  if (t.type == '{' && t.child[0].type == 's')
    return t.child[1];
  return null;
}

DBusBuffer.prototype.readArray = function readArray(eleType, arrayBlobSize) {
  var result;
  var key, value;
  var start = this.pos;

  /*
  if (isHash(eleType)) {
    result = {};
    while(this.pos < start + arrayBlobSize) {
      this.align(3);
      key = this.readTree(eleType.child[0]);
      result[key] = this.readTree(eleType.child[1]);
    }
    console.log('Hash!!!', eleType, parseSignature.fromTree(eleType), result);
    return result;
  }
  */

  // special case: treat ay as Buffer
  if (eleType.type === 'y' && this.options.ayBuffer) {
    this.pos += arrayBlobSize;
    return this.buffer.slice(start, this.pos);
  }

  // end of array is start of first element + array size
  // we need to add 4 bytes if not on 8-byte boundary
  // and array element needs 8 byte alignment
  if (['x', 't', 'd', '{', '(', 'r'].indexOf(eleType.type) != -1)
    this.align(3);
  var end = this.pos + arrayBlobSize;
  result = [];
  while(this.pos < end)
    result.push(this.readTree(eleType));
  return result;
}

DBusBuffer.prototype.readSimpleType = function readSimpleType(t) {
  switch (t) {
  case 'y':
    return this.readInt8();
  case 'b':
    // TODO: spec says that true is strictly 1 and false is strictly 0
    // shold we error (or warn?) when non 01 values?
    return this.readInt32() ? true : false;
  case 'n':
    return this.readSInt16();
  case 'q':
    return this.readInt16();
  case 'u':
    return this.readInt32();
  case 'i':
    return this.readSInt32();
  case 'g':
    var len = this.readInt8();
    return this.readString(len);
  case 's':
  case 'o':
    var len = this.readInt32();
    return this.readString(len);
    // TODO: validate object path here
    //if (t === 'o' && !isValidObjectPath(str))
    //  throw new Error('string is not a valid object path'));
  case 'x': //signed
    this.align(3);
    var word0 = this.readInt32();
    var word1 = this.readInt32();
    var data = Long.fromBits(word0, word1, false);
    if (this.options.ReturnLongjs) return data;
    return data.toNumber(); // convert to number (good up to 53 bits)
  case 't': //unsigned
    this.align(3);
    var word0 = this.readInt32();
    var word1 = this.readInt32();
    var data = Long.fromBits(word0, word1, true);
    if (this.options.ReturnLongjs) return data;
    return data.toNumber(); // convert to number (good up to 53 bits)
  case 'd':
    return this.readDouble();
  default:
    throw new Error('Unsupported type: ' + t);
  }
}

module.exports = DBusBuffer;
<|endoftext|>


<commit_before>import {
  UPDATE_LETTER,
  updateLetter,
  default as letterReducer
} from 'redux/modules/letters'

describe('(Redux Module) Letter', () => {
  it('should export a constant UPDATE_LETTER.', () => {
    expect(UPDATE_LETTER).to.equal('UPDATE_LETTER')
  })
  it('should export a function updateLetter.', () => {
    expect(updateLetter).to.be.a('function')
  })
  it('should export a function letterReducer.', () => {
    expect(letterReducer).to.be.a('function')
  })

  describe('(Action) UPDATE_LETTER', () => {
    it('should update the letter', () => {
      const text = 'a'
      const expectedAction = {
        type: UPDATE_LETTER,
        text
      }
      expect(updateLetter(text)).to.deep.equal(expectedAction)
    })
  })

  describe('(Reducer) Letter', () => {
    it('should return same state if invalid action', () => {
      const initialState = ''
      const expectedState = initialState
      const action = {
        type: 'somethingweird',
        text: 'a'
      }
      expect(letterReducer(initialState, action)).to.deep.equal(expectedState)
    })

    it('should return the new letter in state', () => {
      const initialState = ''
      const text = 'a'
      const expectedState = text
      const action = updateLetter(text)
      expect(letterReducer(initialState, action)).to.deep.equal(expectedState)
    })
  })
})
<commit_msg>refactor letters.spec.js and add more test cases<commit_after>import {
  UPDATE_LETTER,
  updateLetter,
  default as letterReducer
} from 'redux/modules/letters'

describe('(Redux Module) Letter', () => {
  it('should export a constant UPDATE_LETTER.', () => {
    expect(UPDATE_LETTER).to.equal('UPDATE_LETTER')
  })
  it('should export a function updateLetter.', () => {
    expect(updateLetter).to.be.a('function')
  })
  it('should export a function letterReducer.', () => {
    expect(letterReducer).to.be.a('function')
  })

  describe('(Action) UPDATE_LETTER', () => {
    it('should update the letter', () => {
      const text = 'a'
      const expectedAction = {
        type: UPDATE_LETTER,
        text
      }
      expect(updateLetter(text)).to.deep.equal(expectedAction)
    })
  })

  describe('(Reducer) Letter', () => {
    let tests = [
      {
        should: 'should return same state if invalid action type',
        initialState: '',
        expectedState: '',
        action: {
          type: 'somethingweird',
          text: 'a'
        }
      },
      {
        should: 'should return letter if no initial state',
        initialState: undefined,
        expectedState: 'a',
        action: {
          type: 'UPDATE_LETTER',
          text: 'a'
        }
      },
      {
        should: 'should return \'\' if no initial state and no letter',
        initialState: undefined,
        expectedState: '',
        action: {
          type: 'UPDATE_LETTER',
        }
      },
      {
        should: 'should return the new letter in state',
        initialState: '',
        action: {
          type: 'UPDATE_LETTER',
          text: 'a'
        },
        expectedState: 'a'
      },
    ]

    tests.forEach(({should, initialState, expectedState, action}) => {
      it(should, () => {
        expect(letterReducer(initialState, action)).to.equal(expectedState)
      })
    })
  })
})
<|endoftext|>


<commit_before>/* packs the given codebook into the bitstream **************************/

function vorbis_staticbook_pack(c, opb) {
  NOT_IMPLEMENTED();
}

/* unpacks a codebook from the packet buffer into the codebook struct,
   readies the codebook auxiliary structures for decode *************/
function vorbis_staticbook_unpack(opb) {
  NOT_IMPLEMENTED();
}

/* returns the number of bits ************************************************/
function vorbis_book_encode(book, a, b) {
  NOT_IMPLEMENTED();
}

function decode_packed_entry_number(book, b) {
  NOT_IMPLEMENTED();
}

/* Decode side is specced and easier, because we don't need to find
   matches using different criteria; we simply read and map.  There are
   two things we need to do 'depending':

   We may need to support interleave.  We don't really, but it's
   convenient to do it here rather than rebuild the vector later.

   Cascades may be additive or multiplicitive; this is not inherent in
   the codebook, but set in the code using the codebook.  Like
   interleaving, it's easiest to do it here.
   addmul==0 -> declarative (set the value)
   addmul==1 -> additive
   addmul==2 -> multiplicitive */

/* returns the [original, not compacted] entry number or -1 on eof *********/
function vorbis_book_decode(book, b) {
  NOT_IMPLEMENTED();
}

/* returns 0 on OK or -1 on eof *************************************/
/* decode vector / dim granularity gaurding is done in the upper layer */
function vorbis_book_decodevs_add(book, a, b, n) {
  NOT_IMPLEMENTED();
}

/* decode vector / dim granularity gaurding is done in the upper layer */
function vorbis_book_decodev_add(book, a, b, n) {
  NOT_IMPLEMENTED();
}

/* unlike the others, we guard against n not being an integer number
   of <dim> internally rather than in the upper layer (called only by
   floor0) */
function vorbis_book_decodev_set(book, a, b, n) {
  NOT_IMPLEMENTED();
}

function vorbis_book_decodevv_add(book, a, offset, ch, b, n) {
  NOT_IMPLEMENTED();
}
<commit_msg>added: vorbis_staticbook_unpack<commit_after>/* packs the given codebook into the bitstream **************************/

function vorbis_staticbook_pack(c, opb) {
  NOT_IMPLEMENTED();
}

/* unpacks a codebook from the packet buffer into the codebook struct,
   readies the codebook auxiliary structures for decode *************/
function vorbis_staticbook_unpack(opb) {
  var i,j,unused,num,length,quantvals;
  var s=static_codebook();
  s.allocedp=1;

  err_out:while(1){
    /* make sure alignment is correct */
    if(oggpack_read(opb,24)!==0x564342)break err_out; // _eofout;

    /* first the basic parameters */
    s.dim=oggpack_read(opb,16);
    s.entries=oggpack_read(opb,24);
    if(s.entries===-1)break err_out; // _eofout;

    if(ilog(s.dim)+ilog(s.entries)>24)break err_out; // _eofout;

    /* codeword ordering.... length ordered or unordered? */
    switch(oggpack_read(opb,1)){
    case 0:
      /* allocated but unused entries? */
      unused=oggpack_read(opb,1);
      if((s.entries*(unused?1:5)+7)>>3>opb.storage-oggpack_bytes(opb))
        break err_out; // _eofout;
      /* unordered */
      s.lengthlist=calloc(s.entries,int32);

      /* allocated but unused entries? */
      if(unused){
        /* yes, unused entries */

        for(i=0;i<s.entries;i++){
          if(oggpack_read(opb,1)){
            num=oggpack_read(opb,5);
            if(num===-1)break err_out; // _eofout;
            s.lengthlist[i]=num+1;
          }else
            s.lengthlist[i]=0;
        }
      }else{
        /* all entries used; no tagging */
        for(i=0;i<s.entries;i++){
          num=oggpack_read(opb,5);
          if(num===-1)break err_out; // _eofout;
          s.lengthlist[i]=num+1;
        }
      }
      break;
    case 1:
      /* ordered */
      length=oggpack_read(opb,5)+1;
      if(length===0)break err_out; // _eofout;
      s.lengthlist=calloc(s.entries,int32);

      for(i=0;i<s.entries;){
        num=oggpack_read(opb,ilog(s.entries-i));
        if(num===-1)break err_out; // _eofout;
        if(length>32 || num>s.entries-i ||
           (num>0 && (num-1)>>(length-1)>1)){
          break err_out; // _errout;
        }
        if(length>32)break err_out; // _errout;
        for(j=0;j<num;j++,i++)
          s.lengthlist[i]=length;
        length++;
      }
      break;
    default:
      /* EOF */
      break err_out; // _eofout;
    }

    /* Do we have a mapping to unpack? */
    switch((s.maptype=oggpack_read(opb,4))){
    case 0:
      /* no mapping */
      break;
    case 1: case 2:
      /* implicitly populated value mapping */
      /* explicitly populated value mapping */

      s.q_min=oggpack_read(opb,32);
      s.q_delta=oggpack_read(opb,32);
      s.q_quant=oggpack_read(opb,4)+1;
      s.q_sequencep=oggpack_read(opb,1);
      if(s.q_sequencep===-1)break err_out; // _eofout;

      {
        quantvals=0;
        switch(s.maptype){
        case 1:
          quantvals=(s.dim===0?0:_book_maptype1_quantvals(s));
          break;
        case 2:
          quantvals=s.entries*s.dim;
          break;
        }

        /* quantized values */
        if(((quantvals*s.q_quant+7)>>3)>opb.storage-oggpack_bytes(opb))
          break err_out; // _eofout;
        s.quantlist=calloc(quantvals,int32);
        for(i=0;i<quantvals;i++)
          s.quantlist[i]=oggpack_read(opb,s.q_quant);

        if(quantvals&&s.quantlist[quantvals-1]===-1)break err_out; // _eofout;
      }
      break;
    default:
      break err_out; // _errout;
    }

    /* all set */
    return(s);
  }

  // _errout:
  // _eofout:
  vorbis_staticbook_destroy(s);
  return(NULL);
}

/* returns the number of bits ************************************************/
function vorbis_book_encode(book, a, b) {
  NOT_IMPLEMENTED();
}

function decode_packed_entry_number(book, b) {
  NOT_IMPLEMENTED();
}

/* Decode side is specced and easier, because we don't need to find
   matches using different criteria; we simply read and map.  There are
   two things we need to do 'depending':

   We may need to support interleave.  We don't really, but it's
   convenient to do it here rather than rebuild the vector later.

   Cascades may be additive or multiplicitive; this is not inherent in
   the codebook, but set in the code using the codebook.  Like
   interleaving, it's easiest to do it here.
   addmul==0 -> declarative (set the value)
   addmul==1 -> additive
   addmul==2 -> multiplicitive */

/* returns the [original, not compacted] entry number or -1 on eof *********/
function vorbis_book_decode(book, b) {
  NOT_IMPLEMENTED();
}

/* returns 0 on OK or -1 on eof *************************************/
/* decode vector / dim granularity gaurding is done in the upper layer */
function vorbis_book_decodevs_add(book, a, b, n) {
  NOT_IMPLEMENTED();
}

/* decode vector / dim granularity gaurding is done in the upper layer */
function vorbis_book_decodev_add(book, a, b, n) {
  NOT_IMPLEMENTED();
}

/* unlike the others, we guard against n not being an integer number
   of <dim> internally rather than in the upper layer (called only by
   floor0) */
function vorbis_book_decodev_set(book, a, b, n) {
  NOT_IMPLEMENTED();
}

function vorbis_book_decodevv_add(book, a, offset, ch, b, n) {
  NOT_IMPLEMENTED();
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2011 Rackspace
 *
 *  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
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

/** [en|de]coder for cassandra types. */
var BigInteger = require('./bigint').BigInteger;
var UUID = require('./uuid').UUID;

// remember: values x such that -2^31 > x or x > 2^31-1 will make this routine puke.
var bytesToNum = module.exports.bytesToNum = function(bytes) {
  var num = 0;
  // if the sign bit is on, start wtih every bit asserted.  we only care about 32 bits because we lose precision after
  // that anyway.
  if ((0x0080 & bytes.charCodeAt(0)) === 0x0080) {
    num = 0xffffffff;
  }
  for (var i = 0; i < bytes.length; i++) {
    num <<= 8;
    num |= bytes.charCodeAt(i);
  }
  return num;
};

var bytesToBigInt = module.exports.bytesToBigInt = function(bytes) {
  // convert bytes (which is really a string) to a list of ints. then convert the bytes (ints) to a big integer.
  var ints = [];
  for (var i = 0; i < bytes.length; i++) {
    ints[i] = bytes.charCodeAt(i); // how does this handle negative values (bytes that overflow 127)?
    if (ints[i] > 255) {
      throw new Error('Invalid character in packed string ' + ints[i]);
    }
  }
  return new BigInteger(ints);
};

/** convert an 8 byte string to a BigInteger */
var bytesToBigLong = module.exports.bytesToBigLong = function(bytes) {
  if (bytes.length != 8) {
    throw new Error('Longs are exactly 8 bytes, not ' + bytes.length);
  }

  // trim all leading zeros except the most significant one (we don't want to flip signs)
  while (bytes.charCodeAt(0) === 0 && bytes.charCodeAt(1) === 0) {
    bytes = bytes.substr(1);
  }

  // zero is a tricky bastard. new BigInteger([0]) != new BigInteger('0'). wtf?
  if (bytes.length === 1 && bytes.charCodeAt(0) === 0) {
    return new BigInteger('0');
  } else {
    return bytesToBigInt(bytes);
  }

};

// These are the cassandra types I'm currently dealing with.
var AbstractTypes = {
  LongType:     'org.apache.cassandra.db.marshal.LongType',
  BytesType:    'org.apache.cassandra.db.marshal.BytesType',
  AsciiType:    'org.apache.cassandra.db.marshal.AsciiType',
  UTF8Type:     'org.apache.cassandra.db.marshal.UTF8Type',
  IntegerType:  'org.apache.cassandra.db.marshal.IntegerType',
  TimeUUIDType: 'org.apache.cassandra.db.marshal.TimeUUIDType',
  CounterColumnType: 'org.apache.cassandra.db.marshal.CounterColumnType'
};

/**
 * validators are a hash currently created in the Connection constructor. keys in the hash are: key, comparator,
 * defaultValidator, specificValidator.  They all map to a value in AbstractTypes, except specificValidator which
 * hashes to another map that maps specific column names to their validators (specified in ColumnDef using Cassandra
 * parlance).
 * e.g.: {key: 'org.apache.cassandra.db.marshal.BytesType',
 *        comparator: 'org.apache.cassandra.db.marshal.BytesType',
 *        defaultValidator: 'org.apache.cassandra.db.marshal.BytesType',
 *        specificValidator: {your_mother: 'org.apache.cassandra.db.marshal.BytesType',
 *                            my_mother: 'org.apache.cassandra.db.marshal.BytesType'}}
 * todo: maybe this is complicated enough that a class is required.
 */
Decoder = module.exports.Decoder = function(validators, options) {
  this.validators = validators;
  this.options = options ? options : {};
};

/**
 * @param bytes raw bytes to decode.
 * @param which one of 'key', 'comparator', or 'value'.
 * @param column (optional) when which is 'value' this parameter specifies which column validator is to be used.
 */
Decoder.prototype.decode = function(bytes, which, column) {
  // determine which type we are converting to.
  var className = null;
  if (which == 'key') {
    className = this.validators.key;
  } else if (which == 'comparator') {
    className = this.validators.comparator;
  } else if (which == 'validator') {
    if (column && this.validators.specificValidators[column]) {
      className = this.validators.specificValidators[column];
    } else {
      className = this.validators.defaultValidator;
    }
  }
  if (!className) {
    className = AbstractTypes.BytesType;
  }

  // perform the conversion.
  if (className == AbstractTypes.LongType || className == AbstractTypes.CounterColumnType) {
    if (this.options.use_bigints) {
      return bytesToBigLong(bytes);
    } else {
      return bytesToNum(bytes);
    }
  } else if (className == AbstractTypes.AsciiType || className == AbstractTypes.UTF8Type) {
    return bytes; // already as a string!
  } else if (className == AbstractTypes.BytesType) {
    return bytes;
  } else if (className == AbstractTypes.IntegerType) {
    if (this.options.use_bigints) {
      return bytesToBigInt(bytes);
    } else {
      return bytesToNum(bytes);
    }
  } else if (className == AbstractTypes.TimeUUIDType) {
    return new UUID('binary', bytes);
  } else {
    return bytes;
  }

};
<commit_msg>decoder is aware of byte buffers<commit_after>/*
 *  Copyright 2011 Rackspace
 *
 *  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
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

/** [en|de]coder for cassandra types. */
var BigInteger = require('./bigint').BigInteger;
var UUID = require('./uuid').UUID;

// remember: values x such that -2^31 > x or x > 2^31-1 will make this routine puke.
var bytesToNum = module.exports.bytesToNum = function(bytes) {
  var num = 0;
  // if the sign bit is on, start wtih every bit asserted.  we only care about 32 bits because we lose precision after
  // that anyway.
  if ((0x0080 & bytes[0]) === 0x0080) {
    num = 0xffffffff;
  }
  for (var i = 0; i < bytes.length; i++) {
    num <<= 8;
    num |= bytes[i];
  }
  return num;
};

var bytesToBigInt = module.exports.bytesToBigInt = function(bytes) {
  // convert bytes (which is really a string) to a list of ints. then convert the bytes (ints) to a big integer.
  var ints = [];
  for (var i = 0; i < bytes.length; i++) {
    ints[i] = bytes[i]; // how does this handle negative values (bytes that overflow 127)?
    if (ints[i] > 255) {
      throw new Error('Invalid character in packed string ' + ints[i]);
    }
  }
  return new BigInteger(ints);
};

/** convert an 8 byte string to a BigInteger */
var bytesToBigLong = module.exports.bytesToBigLong = function(bytes) {
  if (bytes.length != 8) {
    throw new Error('Longs are exactly 8 bytes, not ' + bytes.length);
  }

  // trim all leading zeros except the most significant one (we don't want to flip signs)
  while (bytes[0] === 0 && bytes[1] === 0) {
    bytes = bytes.slice(1);
  }

  // zero is a tricky bastard. new BigInteger([0]) != new BigInteger('0'). wtf?
  if (bytes.length === 1 && bytes[0] === 0) {
    return new BigInteger('0');
  } else {
    return bytesToBigInt(bytes);
  }

};

// These are the cassandra types I'm currently dealing with.
var AbstractTypes = {
  LongType:     'org.apache.cassandra.db.marshal.LongType',
  BytesType:    'org.apache.cassandra.db.marshal.BytesType',
  AsciiType:    'org.apache.cassandra.db.marshal.AsciiType',
  UTF8Type:     'org.apache.cassandra.db.marshal.UTF8Type',
  IntegerType:  'org.apache.cassandra.db.marshal.IntegerType',
  TimeUUIDType: 'org.apache.cassandra.db.marshal.TimeUUIDType',
  CounterColumnType: 'org.apache.cassandra.db.marshal.CounterColumnType'
};

/**
 * validators are a hash currently created in the Connection constructor. keys in the hash are: key, comparator,
 * defaultValidator, specificValidator.  They all map to a value in AbstractTypes, except specificValidator which
 * hashes to another map that maps specific column names to their validators (specified in ColumnDef using Cassandra
 * parlance).
 * e.g.: {key: 'org.apache.cassandra.db.marshal.BytesType',
 *        comparator: 'org.apache.cassandra.db.marshal.BytesType',
 *        defaultValidator: 'org.apache.cassandra.db.marshal.BytesType',
 *        specificValidator: {your_mother: 'org.apache.cassandra.db.marshal.BytesType',
 *                            my_mother: 'org.apache.cassandra.db.marshal.BytesType'}}
 * todo: maybe this is complicated enough that a class is required.
 */
Decoder = module.exports.Decoder = function(validators, options) {
  this.validators = validators;
  this.options = options ? options : {};
};

/**
 * @param bytes raw bytes to decode.
 * @param which one of 'key', 'comparator', or 'value'.
 * @param column (optional) when which is 'value' this parameter specifies which column validator is to be used.
 */
Decoder.prototype.decode = function(bytes, which, column) {
  // determine which type we are converting to.
  var className = null;
  if (which == 'key') {
    className = this.validators.key;
  } else if (which == 'comparator') {
    className = this.validators.comparator;
  } else if (which == 'validator') {
    if (column && this.validators.specificValidators[column]) {
      className = this.validators.specificValidators[column];
    } else {
      className = this.validators.defaultValidator;
    }
  }
  if (!className) {
    className = AbstractTypes.BytesType;
  }

  // perform the conversion.
  if (className == AbstractTypes.LongType || className == AbstractTypes.CounterColumnType) {
    if (this.options.use_bigints) {
      return bytesToBigLong(bytes);
    } else {
      return bytesToNum(bytes);
    }
  } else if (className == AbstractTypes.AsciiType || className == AbstractTypes.UTF8Type) {
    return bytes; // already as a string!
  } else if (className == AbstractTypes.BytesType) {
    return bytes;
  } else if (className == AbstractTypes.IntegerType) {
    if (this.options.use_bigints) {
      return bytesToBigInt(bytes);
    } else {
      return bytesToNum(bytes);
    }
  } else if (className == AbstractTypes.TimeUUIDType) {
    return new UUID('binary', bytes);
  } else {
    return bytes;
  }

};
<|endoftext|>


<commit_before>'use strict';

var zlib_deflate = require('./zlib/deflate.js');
var utils = require('./zlib/utils');
var c = require('./zlib/constants');
var msg = require('./zlib/messages');
var zstream = require('./zlib/zstream');

/**
 * Deflate
 *
 * @param {Object} [options] zlib options
 * @constructor
 */
var Deflate = function(options) {

  this.options = utils.assign({
    level: 6,
    method: c.Z_DEFLATED,
    chunkSize: 16384,
    windowBits: 15,
    memLevel: 8,
    strategy: c.Z_DEFAULT_STRATEGY
  }, options || {});

  var opt = this.options;

  if (opt.raw && (opt.windowBits > 0)) {
    opt.windowBits = -opt.windowBits;
  }

  else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
    opt.windowBits += 16;
  }

  this.strm = new zstream();

  var status = zlib_deflate.deflateInit2(
    this.strm,
    opt.level,
    opt.method,
    opt.windowBits,
    opt.memLevel,
    opt.strategy
  );

  if (status !== c.Z_OK) {
    throw new Error(msg[status]);
  }
};

/**
 * Compresses the input data and fills output buffer with compressed data.
 */
Deflate.prototype.push = function(data_in) {
  var strm = this.strm;
  var chunkSize = this.options.chunkSize;
  var sliced;

  strm.next_in = data_in;
  strm.next_in_index = 0;
  strm.avail_in = strm.next_in.length;
  strm.next_out = utils.arrayCreate(chunkSize);

  /* run deflate() on input until output buffer not full, finish
   compression if all of source has been read in */
  do {
    strm.avail_out = this.options.chunkSize;
    strm.next_out_index = 0;
    zlib_deflate.deflate(strm, c.Z_NO_FLUSH);
    // TODO: check logic & why onEnd called. Check that onEnd not called twice.
    //var ret = zlib_deflate.deflate(strm, c.Z_NO_FLUSH);    /* no bad return value */
    //if (ret !== c.Z_STREAM_END && ret !== c.Z_OK) {
    //  this.onEnd(ret);
    //}
    if(strm.next_out_index) {
      if (strm.next_out_index === chunkSize) {
        // out buffer completely filled, push it as is
        this.onData(strm.next_out);
      } else {
        // out buffer partially filled, slice it first
        sliced = utils.arrayCreate(strm.next_out_index);
        utils.arraySet(sliced, strm.next_out, 0, strm.next_out_index, 0);
        this.onData(sliced);
      }
      // Allocate buffer for next chunk
      strm.next_out = utils.arrayCreate(this.options.chunkSize);
    }
  } while (strm.avail_in > 0 || strm.avail_out === 0);
};

Deflate.prototype.flush = function() {
  var strm = this.strm;
  var out, status;

  do {
    strm.avail_out = this.options.chunkSize;
    strm.next_out_index = 0;
    status = zlib_deflate.deflate(strm, c.Z_FINISH);    /* no bad return value */
    if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
      this.onEnd(status);
    }

    if(strm.next_out_index) {
      out = utils.arrayCreate(strm.next_out_index);
      utils.arraySet(out, strm.next_out, 0, strm.next_out_index, 0);
      this.onData(out);
    }
  } while (strm.avail_out === 0);
};

Deflate.prototype.finish = function() {
  this.flush();
  zlib_deflate.deflateEnd(this.strm);
  this.onEnd(c.Z_OK);
};

Deflate.prototype.onData = function(/*data_out*/) {

};

Deflate.prototype.onEnd = function(/*err*/) {

};

exports.Deflate = Deflate;

/**
 * Compresses the input data
 * @param input
 * @param [options]
 * @returns {Array|Uint8Array}
 */
function deflate(input, options) {
  var result;
  var chunks = [];
  var deflator = new Deflate(options);

  deflator.onData = function(data_out) {
    chunks.push(data_out);
  };

  deflator.onEnd = function(error) {
    if (error) { throw error; }
    result = utils.flattenChunks(chunks);
  };

  deflator.push(input);
  deflator.finish();

  return result;
}

function deflateRaw(input, options) {
  options = options || {};
  options.raw = true;
  return deflate(input, options);
}

function gzip(input, options) {
  options = options || {};
  options.gzip = true;
  return deflate(input, options);
}

exports.Deflate = Deflate;
exports.deflate = deflate;
exports.deflateRaw = deflateRaw;
exports.gzip = gzip;<commit_msg>Updated wrapper interface and added docs<commit_after>'use strict';

var zlib_deflate = require('./zlib/deflate.js');
var utils = require('./zlib/utils');
var c = require('./zlib/constants');
var msg = require('./zlib/messages');
var zstream = require('./zlib/zstream');

// return sliced buffer, trying to avoid new objects creation and mem copy
function sliceBuf(buf, size) {
  if (buf.length === size) { return buf; }

  var sliced = utils.arrayCreate(size);
  utils.arraySet(sliced, buf, 0, size, 0);
  return sliced;
}

/**
 * new Deflate(ootions)
 *
 * - options (Object): zlib deflate options.
 *
 * Creates new deflator instance with specified params. Supported options:
 *
 * - level
 * - windowBits
 * - memLevel
 * - strategy
 *
 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
 * for more information on these.
 *
 * Additional options, for internal needs:
 *
 * - chunkSize
 * - raw (boolean) - do raw deflate
 * - gzip (boolean) - create gzip wrapper
 */
var Deflate = function(options) {

  this.options = utils.assign({
    level: 6,
    method: c.Z_DEFLATED,
    chunkSize: 16384,
    windowBits: 15,
    memLevel: 8,
    strategy: c.Z_DEFAULT_STRATEGY
  }, options || {});

  var opt = this.options;

  if (opt.raw && (opt.windowBits > 0)) {
    opt.windowBits = -opt.windowBits;
  }

  else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
    opt.windowBits += 16;
  }

  this.ended = false; // used to avoid multiple onEnd() calls
  this.chunks = [];   // chunks of compressed data

  this.strm = new zstream();

  var status = zlib_deflate.deflateInit2(
    this.strm,
    opt.level,
    opt.method,
    opt.windowBits,
    opt.memLevel,
    opt.strategy
  );

  if (status !== c.Z_OK) {
    throw new Error(msg[status]);
  }
};

/**
 * Deflate#push(data) -> boolean
 *
 * - data (Uint8Array|Array) input data
 *
 * Compress input data, generating [Deflate.onData] calls with new data chunks.
 * On fail call [Deflate.onEnd] and return false.
 **/
Deflate.prototype.push = function(data) {
  var strm = this.strm;
  var chunkSize = this.options.chunkSize;
  var status;

  if (this.ended) { return false; }

  strm.next_in = data;
  strm.next_in_index = 0;
  strm.avail_in = strm.next_in.length;
  strm.next_out = utils.arrayCreate(chunkSize);

  do {
    strm.avail_out = this.options.chunkSize;
    strm.next_out_index = 0;
    status = zlib_deflate.deflate(strm, c.Z_NO_FLUSH);    /* no bad return value */

    if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
      this.onEnd(status);
      this.ended = true;
      return false;
    }
    if(strm.next_out_index) {
      this.onData(sliceBuf(strm.next_out, strm.next_out_index));
      // Allocate buffer for next chunk
      strm.next_out = utils.arrayCreate(this.options.chunkSize);
    }
  } while (strm.avail_in > 0 || strm.avail_out === 0);

  return true;
};

/**
 * Deflate#flush() -> boolean
 *
 * Flush internal deflate data to output buffer. Does [Deflate.onData] call on
 * success. On fail call [Deflate.onEnd] and return false.
 **/
Deflate.prototype.flush = function() {
  var strm = this.strm;
  var chunkSize = this.options.chunkSize;
  var status;

  if (this.ended) { return false; }

  strm.next_out = utils.arrayCreate(chunkSize);

  do {
    strm.avail_out = this.options.chunkSize;
    strm.next_out_index = 0;
    status = zlib_deflate.deflate(strm, c.Z_FINISH);    /* no bad return value */

    if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
      this.onEnd(status);
      this.ended = true;
      return false;
    }
    if(strm.next_out_index) {
      this.onData(sliceBuf(strm.next_out, strm.next_out_index));
      // Allocate buffer for next chunk
      strm.next_out = utils.arrayCreate(this.options.chunkSize);
    }
  } while (strm.avail_out === 0);

  return true;
};

/**
 * Deflate#finish() -> boolean
 *
 * Must be called when no more input data available. This function initiates
 * [Deflate#onEnd] call. Returns `false` if something gone wrong.
 **/
Deflate.prototype.finish = function() {
  if (this.ended) { return false; }
  this.flush();
  zlib_deflate.deflateEnd(this.strm);
  this.onEnd(c.Z_OK);
  this.ended = true;
  return true;
};

/**
 * Deflate#onData(chunk) -> Void
 *
 * - chunk (Uint8Array|Array)- ouput data. Type of array depends
 *   on js engine support.
 *
 * By default, it store chunks in [Deflate.chunks]. Override this handler, if
 *  you need another behaviour.
 **/
Deflate.prototype.onData = function(chunk) {
  this.chunks.push(chunk);
};

/**
 * Deflate#onEnd(status) -> Void
 *
 * - status (Number) - deflate status. 0 (Z_OK) on success,
 *   other if not.
 *
 * Called once after you tell deflate that input stream complete. See
 * [Deflate.finish]. By default - join collected chunks, free memory and fill
 * states properties.
 **/
Deflate.prototype.onEnd = function(status) {
  // On success - join
  if (status === c.Z_OK) {
    this.result = utils.flattenChunks(this.chunks);
  }
  this.chunks = [];
  this.err = status;
  // TODO: detect message by status, if not set in zstream
  this.msg = this.strm.msg || msg[status];
  this.ended = true;
};

/**
 * deflate(data, options) -> (Uint8Array|Array)
 *
 * - data (Uint8Array|Array): input data to compress.
 * - options (Object): zlib deflate options.
 *
 * Simple [Deflate] wrapper to compress data with one call.
 *
 * Supported options:
 *
 * - level
 * - windowBits
 * - memLevel
 * - strategy
 *
 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
 * for more information on these.
 **/
function deflate(input, options) {
  var deflator = new Deflate(options);

  deflator.push(input);
  deflator.finish();

  if (deflator.err) { throw msg[deflator.err]; }

  return deflator.result;
}

/**
 * deflateRaw(data, options) -> (Uint8Array|Array)
 *
 * - data (Uint8Array|Array): input data to compress.
 * - options (Object): zlib deflate options.
 *
 * The same as [deflate], but auoput raw data, without wrapper.
 **/
function deflateRaw(input, options) {
  options = options || {};
  options.raw = true;
  return deflate(input, options);
}

/**
 * gzip(data, options) -> (Uint8Array|Array)
 *
 * - data (Uint8Array|Array): input data to compress.
 * - options (Object): zlib deflate options.
 *
 * The same as [deflate], but create gzip wrapper instead of deflate one.
 **/
function gzip(input, options) {
  options = options || {};
  options.gzip = true;
  return deflate(input, options);
}

exports.Deflate = Deflate;
exports.deflate = deflate;
exports.deflateRaw = deflateRaw;
exports.gzip = gzip;<|endoftext|>