<commit_before>// Simple persistence driver that saves data to plain text files

'use strict';

var assign            = require('es5-ext/object/assign')
  , forEach           = require('es5-ext/object/for-each')
  , setPrototypeOf    = require('es5-ext/object/set-prototype-of')
  , toArray           = require('es5-ext/object/to-array')
  , ensureObject      = require('es5-ext/object/valid-object')
  , ensureString      = require('es5-ext/object/validate-stringifiable-value')
  , startsWith        = require('es5-ext/string/#/starts-with')
  , d                 = require('d')
  , memoizeMethods    = require('memoizee/methods')
  , deferred          = require('deferred')
  , resolveKeyPath    = require('dbjs/_setup/utils/resolve-key-path')
  , resolve           = require('path').resolve
  , mkdir             = require('fs2/mkdir')
  , readFile          = require('fs2/read-file')
  , readdir           = require('fs2/readdir')
  , rmdir             = require('fs2/rmdir')
  , writeFile         = require('fs2/write-file')
  , PersistenceDriver = require('./abstract')

  , isId = RegExp.prototype.test.bind(/^[a-z0-9][a-z0-9A-Z]*$/)
  , isArray = Array.isArray, keys = Object.keys, create = Object.create
  , parse = JSON.parse, stringify = JSON.stringify;

var byStamp = function (a, b) {
	return (this[a].stamp - this[b].stamp) || a.toLowerCase().localeCompare(b.toLowerCase());
};

var toComputedFilename = (function () {
	var isIdent   = RegExp.prototype.test.bind(/^[a-z][a-zA-Z0-9]*(?:\/[a-z][a-zA-Z0-9]*)*$/)
	  , slashesRe = /\//g;

	return function (keyPath) {
		return isIdent(keyPath)
			? keyPath.replace(slashesRe, '-')
			: '=' + (new Buffer(keyPath)).toString('base64');
	};
}());

var fromComputedFilename = (function () {
	var dashesRe = /-/g;

	return function (filename) {
		return (filename[0] === '=')
			? String(new Buffer(filename.slice(1), 'base64'))
			: filename.replace(dashesRe, '/');
	};
}());

var resolveObjectMap = function (ownerId, map, keyPaths, result) {
	if (!result) result = create(null);
	forEach(map, function (data, path) {
		if (keyPaths && (path !== '.')) {
			if (!keyPaths.has(resolveKeyPath(ownerId + '/' + path))) return;
		}
		result[(path === '.') ? ownerId : ownerId + '/' + path] = data;
	});
	return result;
};

var TextFileDriver = module.exports = function (dbjs, data) {
	if (!(this instanceof TextFileDriver)) return new TextFileDriver(dbjs, data);
	ensureObject(data);
	this.dirPath = resolve(ensureString(data.path));
	PersistenceDriver.call(this, dbjs, data);
	this.dbDir = mkdir(this.dirPath, { intermediate: true }).aside(null, function (err) {
		this.isClosed = true;
		this.emitError(err);
	}.bind(this));
};
setPrototypeOf(TextFileDriver, PersistenceDriver);

TextFileDriver.prototype = Object.create(PersistenceDriver.prototype, assign({
	constructor: d(TextFileDriver),
	// Any data
	__getRaw: d(function (cat, ns, path) {
		if (cat === 'reduced') {
			return this._getReducedStorage(ns)(function (map) { return map[path || '.'] || null; });
		}
		if (cat === 'computed') {
			return this._getComputedStorage(ns)(function (map) { return map[path] || null; });
		}
		return this._getDirectStorage(ns)(function (map) { return map[path || '.'] || null; });
	}),
	__getDirectObject: d(function (ownerId, keyPaths) {
		return this._getDirectStorage(ownerId)(function (map) {
			return resolveObjectMap(ownerId, map, keyPaths);
		});
	}),
	__getDirectAllObjectIds: d(function () {
		return this.dbDir()(function () {
			var data = create(null);
			return readdir(resolve(this.dirPath, 'direct'), { type: { file: true } })(function (names) {
				return deferred.map(names, function (id) {
					if (!isId(id)) return;
					return this._getDirectStorage(id)(function (map) {
						data[id] = map['.'] || { stamp: 0 };
					});
				}, this)(function () {
					return toArray(data, function (el, id) { return id; }, this, byStamp);
				});
			}.bind(this), function (e) {
				if (e.code === 'ENOENT') return [];
				throw e;
			});
		}.bind(this));
	}),
	__storeRaw: d(function (cat, ns, path, data) {
		if (cat === 'reduced') {
			return this._getReducedStorage(ns)(function (map) {
				map[path || '.'] = data;
				return this._writeStorage('reduced/' + ns, map);
			}.bind(this));
		}
		if (cat === 'computed') {
			return this._getComputedStorage(ns)(function (map) {
				map[path] = data;
				return this._writeStorage('computed/' + toComputedFilename(ns), map);
			}.bind(this));
		}
		return this._getDirectStorage(ns)(function (map) {
			map[path || '.'] = data;
			return this._writeStorage('direct/' + ns, map);
		}.bind(this));
	}),

	// Database data
	__getDirectAll: d(function () {
		return this.__getDirectAllObjectIds().map(function (ownerId) {
			return this._getDirectStorage(ownerId)(function (map) {
				return { ownerId: ownerId, map: map };
			});
		}, this)(function (maps) {
			var result = create(null);
			maps.forEach(function (data) { resolveObjectMap(data.ownerId, data.map, null, result); });
			return result;
		});
	}),

	// Size tracking
	__searchDirect: d(function (keyPath, callback) {
		return this.__getDirectAllObjectIds().map(function (ownerId) {
			return this._getDirectStorage(ownerId)(function (map) {
				if (!keyPath) {
					if (map['.']) callback(ownerId, map['.']);
					return;
				}
				forEach(map, function (data, path) {
					if (!path) return;
					if (keyPath !== path) {
						if (!startsWith.call(path, keyPath + '*')) return;
					}
					callback(ownerId + '/' + path, data);
				});
			});
		}, this);
	}),
	__searchComputed: d(function (keyPath, callback) {
		return this._getComputedStorage(keyPath)(function (map) {
			forEach(map, function (data, ownerId) { callback(ownerId, data); });
		});
	}),

	// Reduced
	__getReducedNs: d(function (ns, keyPaths) {
		return this._getReducedStorage(ns)(function (map) {
			var result = create(null);
			forEach(map, function (data, path) {
				if (path === '.') path = null;
				if (path && keyPaths && !keyPaths.has(path)) return;
				result[ns + (path ? ('/' + path) : '')] = data;
			});
			return result;
		});
	}),

	// Storage import/export
	__exportAll: d(function (destDriver) {
		var count = 0;
		var promise = this.dbDir()(function () {
			return deferred(
				readdir(resolve(this.dirPath, 'direct'), { type: { file: true } }).catch(function (e) {
					if (e.code === 'ENOENT') return [];
					throw e;
				}).map(function (filename) {
					var ownerId = filename;
					return this._getDirectStorage(ownerId)(function (map) {
						return deferred.map(keys(map), function (path) {
							var data = this[path];
							if (path === '.') path = null;
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('direct', ownerId, path, data);
						}, map);
					});
				}.bind(this)),
				readdir(resolve(this.dirPath, 'computed'), { type: { file: true } }).catch(function (e) {
					if (e.code === 'ENOENT') return [];
					throw e;
				}).map(function (filename) {
					var keyPath = fromComputedFilename(filename);
					return this._getComputedStorage(keyPath)(function (map) {
						return deferred.map(keys(map), function (ownerId) {
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('computed', keyPath, ownerId, this[ownerId]);
						}, map);
					});
				}.bind(this)),
				readdir(resolve(this.dirPath, 'reduced'), { type: { file: true } }).catch(function (e) {
					if (e.code === 'ENOENT') return [];
					throw e;
				}).map(function (ns) {
					return this._getReducedStorage(ns)(function (map) {
						return deferred.map(keys(map), function (path) {
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('reduced', ns, (path === '.') ? null : path, this[path]);
						}, map);
					});
				}.bind(this))
			);
		}.bind(this));
		return promise;
	}),
	__clear: d(function () {
		return rmdir(this.dirPath, { recursive: true, force: true })(function () {
			this._getDirectStorage.clear();
			this._getComputedStorage.clear();
			this._getReducedStorage.clear();
			return (this.dbDir = mkdir(this.dirPath, { intermediate: true }));
		}.bind(this));
	}),

	// Connection related
	__close: d(function () { return deferred(undefined); }), // Nothing to close

	_writeStorage: d(function (name, map) {
		return this.dbDir()(function () {
			return writeFile(resolve(this.dirPath, name), toArray(map, function (data, id) {
				var value = data.value;
				if (value === '') value = '-';
				else if (isArray(value)) value = stringify(value);
				return id + '\n' + data.stamp + '\n' + value;
			}, this, byStamp).join('\n\n'), { intermediate: true });
		}.bind(this));
	})
}, memoizeMethods({
	_getDirectStorage: d(function (ownerId) {
		return this.dbDir()(function () {
			var map = create(null);
			return readFile(resolve(this.dirPath, 'direct', ownerId))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						value = data[2];
						if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true }),
	_getComputedStorage: d(function (keyPath) {
		return this.dbDir()(function () {
			var map = create(null), filename = toComputedFilename(keyPath);
			return readFile(resolve(this.dirPath, 'computed', filename))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						value = data[2];
						if (value[0] === '[') value = parse(data[2]);
						else if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true }),
	_getReducedStorage: d(function (ns) {
		return this.dbDir()(function () {
			var map = create(null);
			return readFile(resolve(this.dirPath, 'reduced', ns))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						value = data[2];
						if (value[0] === '[') value = parse(data[2]);
						else if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true })
})));
<commit_msg>Do not crash on empty storage files<commit_after>// Simple persistence driver that saves data to plain text files

'use strict';

var assign            = require('es5-ext/object/assign')
  , forEach           = require('es5-ext/object/for-each')
  , setPrototypeOf    = require('es5-ext/object/set-prototype-of')
  , toArray           = require('es5-ext/object/to-array')
  , ensureObject      = require('es5-ext/object/valid-object')
  , ensureString      = require('es5-ext/object/validate-stringifiable-value')
  , startsWith        = require('es5-ext/string/#/starts-with')
  , d                 = require('d')
  , memoizeMethods    = require('memoizee/methods')
  , deferred          = require('deferred')
  , resolveKeyPath    = require('dbjs/_setup/utils/resolve-key-path')
  , resolve           = require('path').resolve
  , mkdir             = require('fs2/mkdir')
  , readFile          = require('fs2/read-file')
  , readdir           = require('fs2/readdir')
  , rmdir             = require('fs2/rmdir')
  , writeFile         = require('fs2/write-file')
  , PersistenceDriver = require('./abstract')

  , isId = RegExp.prototype.test.bind(/^[a-z0-9][a-z0-9A-Z]*$/)
  , isArray = Array.isArray, keys = Object.keys, create = Object.create
  , parse = JSON.parse, stringify = JSON.stringify;

var byStamp = function (a, b) {
	return (this[a].stamp - this[b].stamp) || a.toLowerCase().localeCompare(b.toLowerCase());
};

var toComputedFilename = (function () {
	var isIdent   = RegExp.prototype.test.bind(/^[a-z][a-zA-Z0-9]*(?:\/[a-z][a-zA-Z0-9]*)*$/)
	  , slashesRe = /\//g;

	return function (keyPath) {
		return isIdent(keyPath)
			? keyPath.replace(slashesRe, '-')
			: '=' + (new Buffer(keyPath)).toString('base64');
	};
}());

var fromComputedFilename = (function () {
	var dashesRe = /-/g;

	return function (filename) {
		return (filename[0] === '=')
			? String(new Buffer(filename.slice(1), 'base64'))
			: filename.replace(dashesRe, '/');
	};
}());

var resolveObjectMap = function (ownerId, map, keyPaths, result) {
	if (!result) result = create(null);
	forEach(map, function (data, path) {
		if (keyPaths && (path !== '.')) {
			if (!keyPaths.has(resolveKeyPath(ownerId + '/' + path))) return;
		}
		result[(path === '.') ? ownerId : ownerId + '/' + path] = data;
	});
	return result;
};

var TextFileDriver = module.exports = function (dbjs, data) {
	if (!(this instanceof TextFileDriver)) return new TextFileDriver(dbjs, data);
	ensureObject(data);
	this.dirPath = resolve(ensureString(data.path));
	PersistenceDriver.call(this, dbjs, data);
	this.dbDir = mkdir(this.dirPath, { intermediate: true }).aside(null, function (err) {
		this.isClosed = true;
		this.emitError(err);
	}.bind(this));
};
setPrototypeOf(TextFileDriver, PersistenceDriver);

TextFileDriver.prototype = Object.create(PersistenceDriver.prototype, assign({
	constructor: d(TextFileDriver),
	// Any data
	__getRaw: d(function (cat, ns, path) {
		if (cat === 'reduced') {
			return this._getReducedStorage(ns)(function (map) { return map[path || '.'] || null; });
		}
		if (cat === 'computed') {
			return this._getComputedStorage(ns)(function (map) { return map[path] || null; });
		}
		return this._getDirectStorage(ns)(function (map) { return map[path || '.'] || null; });
	}),
	__getDirectObject: d(function (ownerId, keyPaths) {
		return this._getDirectStorage(ownerId)(function (map) {
			return resolveObjectMap(ownerId, map, keyPaths);
		});
	}),
	__getDirectAllObjectIds: d(function () {
		return this.dbDir()(function () {
			var data = create(null);
			return readdir(resolve(this.dirPath, 'direct'), { type: { file: true } })(function (names) {
				return deferred.map(names, function (id) {
					if (!isId(id)) return;
					return this._getDirectStorage(id)(function (map) {
						data[id] = map['.'] || { stamp: 0 };
					});
				}, this)(function () {
					return toArray(data, function (el, id) { return id; }, this, byStamp);
				});
			}.bind(this), function (e) {
				if (e.code === 'ENOENT') return [];
				throw e;
			});
		}.bind(this));
	}),
	__storeRaw: d(function (cat, ns, path, data) {
		if (cat === 'reduced') {
			return this._getReducedStorage(ns)(function (map) {
				map[path || '.'] = data;
				return this._writeStorage('reduced/' + ns, map);
			}.bind(this));
		}
		if (cat === 'computed') {
			return this._getComputedStorage(ns)(function (map) {
				map[path] = data;
				return this._writeStorage('computed/' + toComputedFilename(ns), map);
			}.bind(this));
		}
		return this._getDirectStorage(ns)(function (map) {
			map[path || '.'] = data;
			return this._writeStorage('direct/' + ns, map);
		}.bind(this));
	}),

	// Database data
	__getDirectAll: d(function () {
		return this.__getDirectAllObjectIds().map(function (ownerId) {
			return this._getDirectStorage(ownerId)(function (map) {
				return { ownerId: ownerId, map: map };
			});
		}, this)(function (maps) {
			var result = create(null);
			maps.forEach(function (data) { resolveObjectMap(data.ownerId, data.map, null, result); });
			return result;
		});
	}),

	// Size tracking
	__searchDirect: d(function (keyPath, callback) {
		return this.__getDirectAllObjectIds().map(function (ownerId) {
			return this._getDirectStorage(ownerId)(function (map) {
				if (!keyPath) {
					if (map['.']) callback(ownerId, map['.']);
					return;
				}
				forEach(map, function (data, path) {
					if (!path) return;
					if (keyPath !== path) {
						if (!startsWith.call(path, keyPath + '*')) return;
					}
					callback(ownerId + '/' + path, data);
				});
			});
		}, this);
	}),
	__searchComputed: d(function (keyPath, callback) {
		return this._getComputedStorage(keyPath)(function (map) {
			forEach(map, function (data, ownerId) { callback(ownerId, data); });
		});
	}),

	// Reduced
	__getReducedNs: d(function (ns, keyPaths) {
		return this._getReducedStorage(ns)(function (map) {
			var result = create(null);
			forEach(map, function (data, path) {
				if (path === '.') path = null;
				if (path && keyPaths && !keyPaths.has(path)) return;
				result[ns + (path ? ('/' + path) : '')] = data;
			});
			return result;
		});
	}),

	// Storage import/export
	__exportAll: d(function (destDriver) {
		var count = 0;
		var promise = this.dbDir()(function () {
			return deferred(
				readdir(resolve(this.dirPath, 'direct'), { type: { file: true } }).catch(function (e) {
					if (e.code === 'ENOENT') return [];
					throw e;
				}).map(function (filename) {
					var ownerId = filename;
					return this._getDirectStorage(ownerId)(function (map) {
						return deferred.map(keys(map), function (path) {
							var data = this[path];
							if (path === '.') path = null;
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('direct', ownerId, path, data);
						}, map);
					});
				}.bind(this)),
				readdir(resolve(this.dirPath, 'computed'), { type: { file: true } }).catch(function (e) {
					if (e.code === 'ENOENT') return [];
					throw e;
				}).map(function (filename) {
					var keyPath = fromComputedFilename(filename);
					return this._getComputedStorage(keyPath)(function (map) {
						return deferred.map(keys(map), function (ownerId) {
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('computed', keyPath, ownerId, this[ownerId]);
						}, map);
					});
				}.bind(this)),
				readdir(resolve(this.dirPath, 'reduced'), { type: { file: true } }).catch(function (e) {
					if (e.code === 'ENOENT') return [];
					throw e;
				}).map(function (ns) {
					return this._getReducedStorage(ns)(function (map) {
						return deferred.map(keys(map), function (path) {
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('reduced', ns, (path === '.') ? null : path, this[path]);
						}, map);
					});
				}.bind(this))
			);
		}.bind(this));
		return promise;
	}),
	__clear: d(function () {
		return rmdir(this.dirPath, { recursive: true, force: true })(function () {
			this._getDirectStorage.clear();
			this._getComputedStorage.clear();
			this._getReducedStorage.clear();
			return (this.dbDir = mkdir(this.dirPath, { intermediate: true }));
		}.bind(this));
	}),

	// Connection related
	__close: d(function () { return deferred(undefined); }), // Nothing to close

	_writeStorage: d(function (name, map) {
		return this.dbDir()(function () {
			return writeFile(resolve(this.dirPath, name), toArray(map, function (data, id) {
				var value = data.value;
				if (value === '') value = '-';
				else if (isArray(value)) value = stringify(value);
				return id + '\n' + data.stamp + '\n' + value;
			}, this, byStamp).join('\n\n'), { intermediate: true });
		}.bind(this));
	})
}, memoizeMethods({
	_getDirectStorage: d(function (ownerId) {
		return this.dbDir()(function () {
			var map = create(null);
			return readFile(resolve(this.dirPath, 'direct', ownerId))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						if (!data[0] || !data[1] || !data[2]) return;
						value = data[2];
						if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true }),
	_getComputedStorage: d(function (keyPath) {
		return this.dbDir()(function () {
			var map = create(null), filename = toComputedFilename(keyPath);
			return readFile(resolve(this.dirPath, 'computed', filename))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						if (!data[0] || !data[1] || !data[2]) return;
						value = data[2];
						if (value[0] === '[') value = parse(data[2]);
						else if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true }),
	_getReducedStorage: d(function (ns) {
		return this.dbDir()(function () {
			var map = create(null);
			return readFile(resolve(this.dirPath, 'reduced', ns))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						if (!data[0] || !data[1] || !data[2]) return;
						value = data[2];
						if (value[0] === '[') value = parse(data[2]);
						else if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true })
})));
<|endoftext|>


<commit_before>var url = require("url");
var http = require("http");
var https = require("https");
var assert = require("assert");
var Writable = require("stream").Writable;
var debug = require("debug")("follow-redirects");

// RFC7231§4.2.1: Of the request methods defined by this specification,
// the GET, HEAD, OPTIONS, and TRACE methods are defined to be safe.
var SAFE_METHODS = { GET: true, HEAD: true, OPTIONS: true, TRACE: true };

// Create handlers that pass events from native requests
var eventHandlers = Object.create(null);
["abort", "aborted", "error", "socket", "timeout"].forEach(function (event) {
  eventHandlers[event] = function (arg) {
    this._redirectable.emit(event, arg);
  };
});

// An HTTP(S) request that can be redirected
function RedirectableRequest(options, responseCallback) {
  // Initialize the request
  Writable.call(this);
  options.headers = options.headers || {};
  this._options = options;
  this._redirectCount = 0;
  this._redirects = [];
  this._requestBodyLength = 0;
  this._requestBodyBuffers = [];

  // Attach a callback if passed
  if (responseCallback) {
    this.on("response", responseCallback);
  }

  // React to responses of native requests
  var self = this;
  this._onNativeResponse = function (response) {
    self._processResponse(response);
  };

  // Complete the URL object when necessary
  if (!options.pathname && options.path) {
    var searchPos = options.path.indexOf("?");
    if (searchPos < 0) {
      options.pathname = options.path;
    }
    else {
      options.pathname = options.path.substring(0, searchPos);
      options.search = options.path.substring(searchPos);
    }
  }

  // Perform the first request
  this._performRequest();
}
RedirectableRequest.prototype = Object.create(Writable.prototype);

// Writes buffered data to the current native request
RedirectableRequest.prototype.write = function (data, encoding, callback) {
  // Validate input and shift parameters if necessary
  if (!(typeof data === "string" || typeof data === "object" && ("length" in data))) {
    throw new Error("data should be a string, Buffer or Uint8Array");
  }
  if (typeof encoding === "function") {
    callback = encoding;
    encoding = null;
  }

  // Ignore empty buffers, since writing them doesn't invoke the callback
  // https://github.com/nodejs/node/issues/22066
  if (data.length === 0) {
    if (callback) {
      callback();
    }
    return;
  }
  // Only write when we don't exceed the maximum body length
  if (this._requestBodyLength + data.length <= this._options.maxBodyLength) {
    this._requestBodyLength += data.length;
    this._requestBodyBuffers.push({ data: data, encoding: encoding });
    this._currentRequest.write(data, encoding, callback);
  }
  // Error when we exceed the maximum body length
  else {
    this.emit("error", new Error("Request body larger than maxBodyLength limit"));
    this.abort();
  }
};

// Ends the current native request
RedirectableRequest.prototype.end = function (data, encoding, callback) {
  // Shift parameters if necessary
  if (typeof data === "function") {
    callback = data;
    data = encoding = null;
  }
  else if (typeof encoding === "function") {
    callback = encoding;
    encoding = null;
  }

  var currentRequest = this._currentRequest;
  if (!data) {
    currentRequest.end(null, null, callback);
  }
  else {
    this.write(data, encoding, function () {
      currentRequest.end(null, null, callback);
    });
  }
};

// Sets a header value on the current native request
RedirectableRequest.prototype.setHeader = function (name, value) {
  this._options.headers[name] = value;
  this._currentRequest.setHeader(name, value);
};

// Clears a header value on the current native request
RedirectableRequest.prototype.removeHeader = function (name) {
  delete this._options.headers[name];
  this._currentRequest.removeHeader(name);
};

// Proxy all other public ClientRequest methods
[
  "abort", "flushHeaders", "getHeader",
  "setNoDelay", "setSocketKeepAlive", "setTimeout",
].forEach(function (method) {
  RedirectableRequest.prototype[method] = function (a, b) {
    return this._currentRequest[method](a, b);
  };
});

// Proxy all public ClientRequest properties
["aborted", "connection", "socket"].forEach(function (property) {
  Object.defineProperty(RedirectableRequest.prototype, property, {
    get: function () { return this._currentRequest[property]; },
  });
});

// Executes the next native request (initial or redirect)
RedirectableRequest.prototype._performRequest = function () {
  // Load the native protocol
  var protocol = this._options.protocol;
  var nativeProtocol = this._options.nativeProtocols[protocol];
  if (!nativeProtocol) {
    this.emit("error", new Error("Unsupported protocol " + protocol));
    return;
  }

  // If specified, use the agent corresponding to the protocol
  // (HTTP and HTTPS use different types of agents)
  if (this._options.agents) {
    var scheme = protocol.substr(0, protocol.length - 1);
    this._options.agent = this._options.agents[scheme];
  }

  // Create the native request
  var request = this._currentRequest =
        nativeProtocol.request(this._options, this._onNativeResponse);
  this._currentUrl = url.format(this._options);

  // Set up event handlers
  request._redirectable = this;
  for (var event in eventHandlers) {
    /* istanbul ignore else */
    if (event) {
      request.on(event, eventHandlers[event]);
    }
  }

  // End a redirected request
  // (The first request must be ended explicitly with RedirectableRequest#end)
  if (this._isRedirect) {
    // Write the request entity and end.
    var i = 0;
    var buffers = this._requestBodyBuffers;
    (function writeNext() {
      if (i < buffers.length) {
        var buffer = buffers[i++];
        request.write(buffer.data, buffer.encoding, writeNext);
      }
      else {
        request.end();
      }
    }());
  }
};

// Processes a response from the current native request
RedirectableRequest.prototype._processResponse = function (response) {
  // Store the redirected response
  if (this._options.trackRedirects) {
    this._redirects.push({
      url: this._currentUrl,
      headers: response.headers,
      statusCode: response.statusCode,
    });
  }

  // RFC7231§6.4: The 3xx (Redirection) class of status code indicates
  // that further action needs to be taken by the user agent in order to
  // fulfill the request. If a Location header field is provided,
  // the user agent MAY automatically redirect its request to the URI
  // referenced by the Location field value,
  // even if the specific status code is not understood.
  var location = response.headers.location;
  if (location && this._options.followRedirects !== false &&
      response.statusCode >= 300 && response.statusCode < 400) {
    // RFC7231§6.4: A client SHOULD detect and intervene
    // in cyclical redirections (i.e., "infinite" redirection loops).
    if (++this._redirectCount > this._options.maxRedirects) {
      this.emit("error", new Error("Max redirects exceeded."));
      return;
    }

    // RFC7231§6.4: Automatic redirection needs to done with
    // care for methods not known to be safe […],
    // since the user might not wish to redirect an unsafe request.
    // RFC7231§6.4.7: The 307 (Temporary Redirect) status code indicates
    // that the target resource resides temporarily under a different URI
    // and the user agent MUST NOT change the request method
    // if it performs an automatic redirection to that URI.
    var header;
    var headers = this._options.headers;
    if (response.statusCode !== 307 && !(this._options.method in SAFE_METHODS)) {
      this._options.method = "GET";
      // Drop a possible entity and headers related to it
      this._requestBodyBuffers = [];
      for (header in headers) {
        if (/^content-/i.test(header)) {
          delete headers[header];
        }
      }
    }

    // Drop the Host header, as the redirect might lead to a different host
    if (!this._isRedirect) {
      for (header in headers) {
        if (/^host$/i.test(header)) {
          delete headers[header];
        }
      }
    }

    // Perform the redirected request
    var redirectUrl = url.resolve(this._currentUrl, location);
    debug("redirecting to", redirectUrl);
    Object.assign(this._options, url.parse(redirectUrl));
    this._isRedirect = true;
    this._performRequest();

    // Discard the remainder of the response to avoid waiting for data
    response.destroy();
  }
  else {
    // The response is not a redirect; return it as-is
    response.responseUrl = this._currentUrl;
    response.redirects = this._redirects;
    this.emit("response", response);

    // Clean up
    this._requestBodyBuffers = [];
  }
};

// Wraps the key/value object of protocols with redirect functionality
function wrap(protocols) {
  // Default settings
  var exports = {
    maxRedirects: 21,
    maxBodyLength: 10 * 1024 * 1024,
  };

  // Wrap each protocol
  var nativeProtocols = {};
  Object.keys(protocols).forEach(function (scheme) {
    var protocol = scheme + ":";
    var nativeProtocol = nativeProtocols[protocol] = protocols[scheme];
    var wrappedProtocol = exports[scheme] = Object.create(nativeProtocol);

    // Executes a request, following redirects
    wrappedProtocol.request = function (options, callback) {
      if (typeof options === "string") {
        options = url.parse(options);
        options.maxRedirects = exports.maxRedirects;
      }
      else {
        options = Object.assign({
          protocol: protocol,
          maxRedirects: exports.maxRedirects,
          maxBodyLength: exports.maxBodyLength,
        }, options);
      }
      options.nativeProtocols = nativeProtocols;
      assert.equal(options.protocol, protocol, "protocol mismatch");
      debug("options", options);
      return new RedirectableRequest(options, callback);
    };

    // Executes a GET request, following redirects
    wrappedProtocol.get = function (options, callback) {
      var request = wrappedProtocol.request(options, callback);
      request.end();
      return request;
    };
  });
  return exports;
}

// Exports
module.exports = wrap({ http: http, https: https });
module.exports.wrap = wrap;
<commit_msg>Simplify end.<commit_after>var url = require("url");
var http = require("http");
var https = require("https");
var assert = require("assert");
var Writable = require("stream").Writable;
var debug = require("debug")("follow-redirects");

// RFC7231§4.2.1: Of the request methods defined by this specification,
// the GET, HEAD, OPTIONS, and TRACE methods are defined to be safe.
var SAFE_METHODS = { GET: true, HEAD: true, OPTIONS: true, TRACE: true };

// Create handlers that pass events from native requests
var eventHandlers = Object.create(null);
["abort", "aborted", "error", "socket", "timeout"].forEach(function (event) {
  eventHandlers[event] = function (arg) {
    this._redirectable.emit(event, arg);
  };
});

// An HTTP(S) request that can be redirected
function RedirectableRequest(options, responseCallback) {
  // Initialize the request
  Writable.call(this);
  options.headers = options.headers || {};
  this._options = options;
  this._redirectCount = 0;
  this._redirects = [];
  this._requestBodyLength = 0;
  this._requestBodyBuffers = [];

  // Attach a callback if passed
  if (responseCallback) {
    this.on("response", responseCallback);
  }

  // React to responses of native requests
  var self = this;
  this._onNativeResponse = function (response) {
    self._processResponse(response);
  };

  // Complete the URL object when necessary
  if (!options.pathname && options.path) {
    var searchPos = options.path.indexOf("?");
    if (searchPos < 0) {
      options.pathname = options.path;
    }
    else {
      options.pathname = options.path.substring(0, searchPos);
      options.search = options.path.substring(searchPos);
    }
  }

  // Perform the first request
  this._performRequest();
}
RedirectableRequest.prototype = Object.create(Writable.prototype);

// Writes buffered data to the current native request
RedirectableRequest.prototype.write = function (data, encoding, callback) {
  // Validate input and shift parameters if necessary
  if (!(typeof data === "string" || typeof data === "object" && ("length" in data))) {
    throw new Error("data should be a string, Buffer or Uint8Array");
  }
  if (typeof encoding === "function") {
    callback = encoding;
    encoding = null;
  }

  // Ignore empty buffers, since writing them doesn't invoke the callback
  // https://github.com/nodejs/node/issues/22066
  if (data.length === 0) {
    if (callback) {
      callback();
    }
    return;
  }
  // Only write when we don't exceed the maximum body length
  if (this._requestBodyLength + data.length <= this._options.maxBodyLength) {
    this._requestBodyLength += data.length;
    this._requestBodyBuffers.push({ data: data, encoding: encoding });
    this._currentRequest.write(data, encoding, callback);
  }
  // Error when we exceed the maximum body length
  else {
    this.emit("error", new Error("Request body larger than maxBodyLength limit"));
    this.abort();
  }
};

// Ends the current native request
RedirectableRequest.prototype.end = function (data, encoding, callback) {
  // Shift parameters if necessary
  if (typeof data === "function") {
    callback = data;
    data = encoding = null;
  }
  else if (typeof encoding === "function") {
    callback = encoding;
    encoding = null;
  }

  // Write data and end
  var currentRequest = this._currentRequest;
  this.write(data || "", encoding, function () {
    currentRequest.end(null, null, callback);
  });
};

// Sets a header value on the current native request
RedirectableRequest.prototype.setHeader = function (name, value) {
  this._options.headers[name] = value;
  this._currentRequest.setHeader(name, value);
};

// Clears a header value on the current native request
RedirectableRequest.prototype.removeHeader = function (name) {
  delete this._options.headers[name];
  this._currentRequest.removeHeader(name);
};

// Proxy all other public ClientRequest methods
[
  "abort", "flushHeaders", "getHeader",
  "setNoDelay", "setSocketKeepAlive", "setTimeout",
].forEach(function (method) {
  RedirectableRequest.prototype[method] = function (a, b) {
    return this._currentRequest[method](a, b);
  };
});

// Proxy all public ClientRequest properties
["aborted", "connection", "socket"].forEach(function (property) {
  Object.defineProperty(RedirectableRequest.prototype, property, {
    get: function () { return this._currentRequest[property]; },
  });
});

// Executes the next native request (initial or redirect)
RedirectableRequest.prototype._performRequest = function () {
  // Load the native protocol
  var protocol = this._options.protocol;
  var nativeProtocol = this._options.nativeProtocols[protocol];
  if (!nativeProtocol) {
    this.emit("error", new Error("Unsupported protocol " + protocol));
    return;
  }

  // If specified, use the agent corresponding to the protocol
  // (HTTP and HTTPS use different types of agents)
  if (this._options.agents) {
    var scheme = protocol.substr(0, protocol.length - 1);
    this._options.agent = this._options.agents[scheme];
  }

  // Create the native request
  var request = this._currentRequest =
        nativeProtocol.request(this._options, this._onNativeResponse);
  this._currentUrl = url.format(this._options);

  // Set up event handlers
  request._redirectable = this;
  for (var event in eventHandlers) {
    /* istanbul ignore else */
    if (event) {
      request.on(event, eventHandlers[event]);
    }
  }

  // End a redirected request
  // (The first request must be ended explicitly with RedirectableRequest#end)
  if (this._isRedirect) {
    // Write the request entity and end.
    var i = 0;
    var buffers = this._requestBodyBuffers;
    (function writeNext() {
      if (i < buffers.length) {
        var buffer = buffers[i++];
        request.write(buffer.data, buffer.encoding, writeNext);
      }
      else {
        request.end();
      }
    }());
  }
};

// Processes a response from the current native request
RedirectableRequest.prototype._processResponse = function (response) {
  // Store the redirected response
  if (this._options.trackRedirects) {
    this._redirects.push({
      url: this._currentUrl,
      headers: response.headers,
      statusCode: response.statusCode,
    });
  }

  // RFC7231§6.4: The 3xx (Redirection) class of status code indicates
  // that further action needs to be taken by the user agent in order to
  // fulfill the request. If a Location header field is provided,
  // the user agent MAY automatically redirect its request to the URI
  // referenced by the Location field value,
  // even if the specific status code is not understood.
  var location = response.headers.location;
  if (location && this._options.followRedirects !== false &&
      response.statusCode >= 300 && response.statusCode < 400) {
    // RFC7231§6.4: A client SHOULD detect and intervene
    // in cyclical redirections (i.e., "infinite" redirection loops).
    if (++this._redirectCount > this._options.maxRedirects) {
      this.emit("error", new Error("Max redirects exceeded."));
      return;
    }

    // RFC7231§6.4: Automatic redirection needs to done with
    // care for methods not known to be safe […],
    // since the user might not wish to redirect an unsafe request.
    // RFC7231§6.4.7: The 307 (Temporary Redirect) status code indicates
    // that the target resource resides temporarily under a different URI
    // and the user agent MUST NOT change the request method
    // if it performs an automatic redirection to that URI.
    var header;
    var headers = this._options.headers;
    if (response.statusCode !== 307 && !(this._options.method in SAFE_METHODS)) {
      this._options.method = "GET";
      // Drop a possible entity and headers related to it
      this._requestBodyBuffers = [];
      for (header in headers) {
        if (/^content-/i.test(header)) {
          delete headers[header];
        }
      }
    }

    // Drop the Host header, as the redirect might lead to a different host
    if (!this._isRedirect) {
      for (header in headers) {
        if (/^host$/i.test(header)) {
          delete headers[header];
        }
      }
    }

    // Perform the redirected request
    var redirectUrl = url.resolve(this._currentUrl, location);
    debug("redirecting to", redirectUrl);
    Object.assign(this._options, url.parse(redirectUrl));
    this._isRedirect = true;
    this._performRequest();

    // Discard the remainder of the response to avoid waiting for data
    response.destroy();
  }
  else {
    // The response is not a redirect; return it as-is
    response.responseUrl = this._currentUrl;
    response.redirects = this._redirects;
    this.emit("response", response);

    // Clean up
    this._requestBodyBuffers = [];
  }
};

// Wraps the key/value object of protocols with redirect functionality
function wrap(protocols) {
  // Default settings
  var exports = {
    maxRedirects: 21,
    maxBodyLength: 10 * 1024 * 1024,
  };

  // Wrap each protocol
  var nativeProtocols = {};
  Object.keys(protocols).forEach(function (scheme) {
    var protocol = scheme + ":";
    var nativeProtocol = nativeProtocols[protocol] = protocols[scheme];
    var wrappedProtocol = exports[scheme] = Object.create(nativeProtocol);

    // Executes a request, following redirects
    wrappedProtocol.request = function (options, callback) {
      if (typeof options === "string") {
        options = url.parse(options);
        options.maxRedirects = exports.maxRedirects;
      }
      else {
        options = Object.assign({
          protocol: protocol,
          maxRedirects: exports.maxRedirects,
          maxBodyLength: exports.maxBodyLength,
        }, options);
      }
      options.nativeProtocols = nativeProtocols;
      assert.equal(options.protocol, protocol, "protocol mismatch");
      debug("options", options);
      return new RedirectableRequest(options, callback);
    };

    // Executes a GET request, following redirects
    wrappedProtocol.get = function (options, callback) {
      var request = wrappedProtocol.request(options, callback);
      request.end();
      return request;
    };
  });
  return exports;
}

// Exports
module.exports = wrap({ http: http, https: https });
module.exports.wrap = wrap;
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict'

const Bossy = require('bossy')
const sync = require('./sync')

function _(str) {
  return `\u001b[4m${str}\u001b[24m`
}

let definition = {
  h: {
    description: 'Show help',
    alias: 'help',
    type: 'boolean'
  },
  b: {
    description: 'S3 bucket to sync with',
    alias: 'bucket'
  },
  p: {
    description: 'Directory path, defaults to cwd',
    alias: 'path',
    default: process.cwd()
  },
  t: {
    description: 'Sync again every n seconds',
    alias: 'watch',
    type: 'number',
    default: 0
  },
  f: {
    description: 'File filter pattern',
    alias: 'filefilter'
  },
  d: {
    description: 'Directory filter pattern',
    alias: 'dirfilter'
  }
}

let args = Bossy.parse(definition)

if (args instanceof Error) {
  console.error(args.message)
  return
}

if (args.h) {
  console.log(Bossy.usage(definition, `\n  s3sync -b ${_('bucket')} [-p ${_('path')}] [-f ${_('pattern')}] [-d ${_('pattern')}] [-t ${_('n')}]`))
  return
}

function restartSync() {
  if (args.t > 0) {
    setTimeout(startSync, args.t * 1000)
  }
}

function startSync() {

  sync(args.b, args.p, args.f, args.d)
    .then(() => {
      console.log('\nSync completed successfully')
      restartSync()
    })
    .catch(err => {
      console.error(err)
      restartSync()
    })
}

startSync()
<commit_msg>multiple file and dir filters<commit_after>#!/usr/bin/env node

'use strict'

const Bossy = require('bossy')
const sync = require('./sync')

function _(str) {
  return `\u001b[4m${str}\u001b[24m`
}

let definition = {
  h: {
    description: 'Show help',
    alias: 'help',
    type: 'boolean'
  },
  b: {
    description: 'S3 bucket to sync with',
    alias: 'bucket'
  },
  p: {
    description: 'Directory path, defaults to cwd',
    alias: 'path',
    default: process.cwd()
  },
  t: {
    description: 'Sync again every n seconds',
    alias: 'watch',
    type: 'number',
    default: 0
  },
  f: {
    description: 'File filter pattern',
    alias: 'filefilter',
    multiple: true
  },
  d: {
    description: 'Directory filter pattern',
    alias: 'dirfilter',
    multiple: true
  }
}

let args = Bossy.parse(definition)

if (args instanceof Error) {
  console.error(args.message)
  return
}

if (args.h) {
  console.log(Bossy.usage(definition, `\n  s3sync -b ${_('bucket')} [-p ${_('path')}] [-f ${_('pattern')}] [-d ${_('pattern')}] [-t ${_('n')}]`))
  return
}

function restartSync() {
  if (args.t > 0) {
    setTimeout(startSync, args.t * 1000)
  }
}

function startSync() {

  sync(args.b, args.p, args.f, args.d)
    .then(() => {
      console.log('\nSync completed successfully')
      restartSync()
    })
    .catch(err => {
      console.error(err)
      restartSync()
    })
}

startSync()
<|endoftext|>


<commit_before>/**
 * Copyright 2014-2015 David Herron
 *
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

'use strict';

var cheerio = require('cheerio');
var util    = require('util');
var async   = require('async');

var configCheerio;

exports.config = function(_configCheerio) {
    configCheerio = _configCheerio;
};

/**
 * Simply parse the text, returning $ so the caller can do whatever they want.
 */
exports.parse = function(text) {
    return configCheerio ? cheerio.load(text, configCheerio) : cheerio.load(text);
};

exports.Mahafunc = class Mahafunc {
    get selector() { throw new Error("This getter must be overridden"); }

    findElements($) {
        var ret = [];
        $(this.selector).each(function(i, elem) { ret.push(elem); });
        return ret;
    }

    process() { throw new Error("This function must be overridden"); }
    processAll() { throw new Error("This function must be overridden"); }
}

/**
 * Implements an HTML-ish element that is replaced with
 * some other HTML.  For example, <embed-video> might take
 * an href= and other attributes to describe a video from
 * a known service, the process function discerns the HTML code
 * to use for the player, rendering that into the output.
 */
exports.CustomElement = class CustomElement extends exports.Mahafunc {

    get elementName() { throw new Error("This getter must be overridden"); }
	get selector() { return this.elementName; }

    process($element, metadata, setDirty, done) {
        throw new Error("This function must be overridden");
    }

    processAll($, metadata, setDirty, done) {
        // console.log(`CustomElement processAll ${this.elementName}`);
        var elements = this.findElements($);
        if (elements.length <= 0) return done();
        async.eachSeries(elements, (element, next) => {
            try {
                this.process($(element), metadata, setDirty,
                (err, replaceWith) => {
                    if (err) return next(err);
                    $(element).replaceWith(replaceWith);
                    next();
                });
            } catch (err) { next(err); }
        },
        err => {
            // log(`after ak-stylesheets ${metadata.document.path} ${$.html()}`);
            if (err) {
                console.error(`${this.elementName} Errored with ${util.inspect(err)}`);
                done(err);
            } else done();
        });
    }
}

exports.ElementTweaker = class ElementTweaker extends exports.Mahafunc {
    process() {
        throw new Error("This function must be overridden")
    }
}

exports.Munger = class Munger extends exports.Mahafunc {
    process($, $element, metadata, setDirty, done) {
        throw new Error("This function must be overridden")
    }
    processAll($, metadata, setDirty, done) {
        // console.log(`Munger processAll`);
        var elements = this.findElements($);
        // console.log(`Munger for ${this.selector} found ${elements.length} items to process`);
        if (elements.length <= 0) return done();
        async.eachSeries(elements, (element, next) => {
            try {
                this.process($, $(element), metadata, setDirty, next);
            } catch (err) { next(err); }
        },
        err => {
            // log(`after ak-stylesheets ${metadata.document.path} ${$.html()}`);
            if (err) {
                console.error(`${this.selector} Errored with ${util.inspect(err)}`);
                done(err);
            } else {
                // console.log(`Munger finished with ${this.selector}`);
                done();
            }
        });
    }
}

/**
 * Process the text using functions supplied in the array mahabhutaFuncs.
 */
exports.process = function(text, metadata, mahabhutaFuncs, done) {

	// If we were on a Synchronous platform, this might be
	//
	// var cleanOrDirty = 'first-time';
	// while (dirtyOrClean !== 'dirty' && dirtyOrClean !== 'first-time') {
	// 		cleanOrDirty = 'clean';
	//		mahabhutaFuncs.forEach(function(mahafunc) {
	//			mahafunc($, metadata, setDirty, function(err) { ... });
	//      }
	// }

    if (!mahabhutaFuncs || mahabhutaFuncs.length < 0) mahabhutaFuncs = [];

	var cleanOrDirty = 'first-time';
	var setDirty = function() { cleanOrDirty = 'dirty'; };

    // Allow a pre-parsed context to be passed in
    var $ = typeof text === 'function' ? text : exports.parse(text);

    var runMahaArray = function(mahaArray) {
        return new Promise((resolve, reject) => {
            async.eachSeries(mahaArray,
            (mahafunc, next) => {
                // util.log(util.inspect(mahafunc));
                if (mahafunc instanceof exports.CustomElement) {
                    mahafunc.processAll($, metadata, setDirty, next);
                } else if (mahafunc instanceof exports.Munger) {
                    mahafunc.processAll($, metadata, setDirty, next);
                } else if (typeof mahafunc === 'function') {
                    mahafunc($, metadata, setDirty, next);
                } else if (Array.isArray(mahafunc)) {
                    runMahaArray(mahafunc)
                    .then(() => { next(); })
                    .catch(err => { next(err); });
                } else {
                    console.error("BAD MAHAFUNC "+ util.inspect(mahafunc));
                    next();
                }
            },
            err => {
                // console.log(`runMahaArray finished with ${err}`);
                if (err) reject(err);
                else resolve();
            }
            );
        })
    };

    // Keep running the functions until the page is clean
    var runMahaFuncs = function() {
        // console.log(`START RUNMAHAFUNCS`);
    	if (cleanOrDirty === 'dirty' || cleanOrDirty === 'first-time') {
    		cleanOrDirty = 'clean';
            runMahaArray(mahabhutaFuncs)
            .then(() => { runMahaFuncs(); })
            .catch(err => { console.error(`runMahaFuncs finished with ERROR ${err}`); done(err); });
/*			async.eachSeries(mahabhutaFuncs,
				function(mahafunc, next) {
					mahafunc($, metadata, setDirty, function(err) {
						if (err) next(err);
						else next();
					});
				},
				function(err) {
					if (err) done(err);
					else setImmediate(function() { runMahaFuncs(); });
				}); */
		} else {
            // console.log(`runMahaFuncs finished normally`);
			done(undefined, $.html());
		}
	};
	runMahaFuncs();
};

exports.process1 = function(text, metadata, mahafunc, done) {
	exports.process(text, metadata, [ mahafunc ], done);
};

/**
 * The beginnings of Express integration for Mahabhuta.  The only unclarity is
 * the source for the function array.
 * /
exports.express = function(filePath, options, callback) {
	fs.readFile(filePath, function (err, content) {
		if (err) callback(new Error(err));
		else {
			exports.process(content, options, "TBD - FUNCTIONS", function(err, html) {
				if (err) callback(err);
				else callback(null, html);
			});
		}
	})
};*/
<commit_msg>Switch to Promises for Mahafunc classes<commit_after>/**
 * Copyright 2014-2015 David Herron
 *
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

'use strict';

var cheerio = require('cheerio');
var util    = require('util');
var async   = require('async');

var configCheerio;

exports.config = function(_configCheerio) {
    configCheerio = _configCheerio;
};

/**
 * Simply parse the text, returning $ so the caller can do whatever they want.
 */
exports.parse = function(text) {
    return configCheerio ? cheerio.load(text, configCheerio) : cheerio.load(text);
};

exports.Mahafunc = class Mahafunc {
    get selector() { throw new Error("This getter must be overridden"); }

    findElements($) {
        var ret = [];
        $(this.selector).each(function(i, elem) { ret.push(elem); });
        return ret;
    }

    process() { throw new Error("This function must be overridden"); }
    processAll() { throw new Error("This function must be overridden"); }
}

/**
 * Implements an HTML-ish element that is replaced with
 * some other HTML.  For example, <embed-video> might take
 * an href= and other attributes to describe a video from
 * a known service, the process function discerns the HTML code
 * to use for the player, rendering that into the output.
 */
exports.CustomElement = class CustomElement extends exports.Mahafunc {

    get elementName() { throw new Error("This getter must be overridden"); }
	get selector() { return this.elementName; }

    process($element, metadata, setDirty, done) {
        throw new Error("This function must be overridden");
    }

    processAll($, metadata, setDirty, done) {
        // console.log(`CustomElement processAll ${this.elementName}`);
        var elements = this.findElements($);
        if (elements.length <= 0) return done();
        async.eachSeries(elements, (element, next) => {
            this.process($(element), metadata, setDirty)
            .then(replaceWith => {
                $(element).replaceWith(replaceWith);
                next();
            })
            .catch(err => { next(err); });
        },
        err => {
            // log(`after ak-stylesheets ${metadata.document.path} ${$.html()}`);
            if (err) {
                console.error(`CustomElement ${this.elementName} Errored with ${util.inspect(err)}`);
                done(err);
            } else done();
        });
    }
}

exports.ElementTweaker = class ElementTweaker extends exports.Mahafunc {
    process() {
        throw new Error("This function must be overridden")
    }
}

exports.Munger = class Munger extends exports.Mahafunc {
    process($, $element, metadata, setDirty, done) {
        throw new Error("This function must be overridden")
    }
    processAll($, metadata, setDirty, done) {
        // console.log(`Munger processAll`);
        var elements = this.findElements($);
        // console.log(`Munger for ${this.selector} found ${elements.length} items to process`);
        if (elements.length <= 0) return done();
        async.eachSeries(elements, (element, next) => {
            this.process($, $(element), metadata, setDirty)
            .then(() => { next(); })
            .catch(err => { next(err); });
        },
        err => {
            // log(`after ak-stylesheets ${metadata.document.path} ${$.html()}`);
            if (err) {
                console.error(`${this.selector} Errored with ${util.inspect(err)}`);
                done(err);
            } else {
                // console.log(`Munger finished with ${this.selector}`);
                done();
            }
        });
    }
}

/**
 * Process the text using functions supplied in the array mahabhutaFuncs.
 */
exports.process = function(text, metadata, mahabhutaFuncs, done) {

	// If we were on a Synchronous platform, this might be
	//
	// var cleanOrDirty = 'first-time';
	// while (dirtyOrClean !== 'dirty' && dirtyOrClean !== 'first-time') {
	// 		cleanOrDirty = 'clean';
	//		mahabhutaFuncs.forEach(function(mahafunc) {
	//			mahafunc($, metadata, setDirty, function(err) { ... });
	//      }
	// }

    if (!mahabhutaFuncs || mahabhutaFuncs.length < 0) mahabhutaFuncs = [];

	var cleanOrDirty = 'first-time';
	var setDirty = function() { cleanOrDirty = 'dirty'; };

    // Allow a pre-parsed context to be passed in
    var $ = typeof text === 'function' ? text : exports.parse(text);

    var runMahaArray = function(mahaArray) {
        return new Promise((resolve, reject) => {
            async.eachSeries(mahaArray, (mahafunc, next) => {
                // util.log(util.inspect(mahafunc));
                if (mahafunc instanceof exports.CustomElement) {
                    mahafunc.processAll($, metadata, setDirty, next);
                } else if (mahafunc instanceof exports.Munger) {
                    mahafunc.processAll($, metadata, setDirty, next);
                } else if (typeof mahafunc === 'function') {
                    mahafunc($, metadata, setDirty, next);
                } else if (Array.isArray(mahafunc)) {
                    runMahaArray(mahafunc)
                    .then(() => { next(); })
                    .catch(err => { next(err); });
                } else {
                    console.error("BAD MAHAFUNC "+ util.inspect(mahafunc));
                    next();
                }
            },
            err => {
                // console.log(`runMahaArray finished with ${err}`);
                if (err) reject(err);
                else resolve();
            }
            );
        })
    };

    // Keep running the functions until the page is clean
    var runMahaFuncs = function() {
        // console.log(`START RUNMAHAFUNCS`);
    	if (cleanOrDirty === 'dirty' || cleanOrDirty === 'first-time') {
    		cleanOrDirty = 'clean';
            runMahaArray(mahabhutaFuncs)
            .then(() => { runMahaFuncs(); })
            .catch(err => { console.error(`runMahaFuncs finished with ERROR ${err}`); done(err); });
/*			async.eachSeries(mahabhutaFuncs,
				function(mahafunc, next) {
					mahafunc($, metadata, setDirty, function(err) {
						if (err) next(err);
						else next();
					});
				},
				function(err) {
					if (err) done(err);
					else setImmediate(function() { runMahaFuncs(); });
				}); */
		} else {
            // console.log(`runMahaFuncs finished normally`);
			done(undefined, $.html());
		}
	};
	runMahaFuncs();
};

exports.process1 = function(text, metadata, mahafunc, done) {
	exports.process(text, metadata, [ mahafunc ], done);
};

/**
 * The beginnings of Express integration for Mahabhuta.  The only unclarity is
 * the source for the function array.
 * /
exports.express = function(filePath, options, callback) {
	fs.readFile(filePath, function (err, content) {
		if (err) callback(new Error(err));
		else {
			exports.process(content, options, "TBD - FUNCTIONS", function(err, html) {
				if (err) callback(err);
				else callback(null, html);
			});
		}
	})
};*/
<|endoftext|>


<commit_before>'use strict'

require("babel-core").transform("code");

const {ipcRenderer} = require('electron');
const {requireTaskPool} = require('electron-remote');
const {app} = require('electron').remote;

const remote = require('electron').remote,
	  fs = require('fs'),
	  path = require('path'),
	  pImg = requireTaskPool(require.resolve('./imgProcess')),
	  jFiles = path.join(app.getPath('userData'), 'files.json'),
	  unFiles = path.join(app.getPath('userData'), 'unprocessed.json');

let docFrag = document.createDocumentFragment(),
	pFiles = [],
	uArray = [];

// Create window controls and browse functionality
(function() {
	document.getElementById('min-btn').addEventListener('click', () => {
		remote.getCurrentWindow().minimize();
	}, false);

	document.getElementById('max-btn').addEventListener('click', () => {
		if (!remote.getCurrentWindow().isMaximized()) {
			remote.getCurrentWindow().maximize();
		} else {
			remote.getCurrentWindow().unmaximize();
		}
	}, false);

	document.getElementById('close-btn').addEventListener('click', () => {

		// Add processed images to files.json if app quit before finishing
		// Figure out a way to run an app.quit() after adding files. PROMISES!
		if (pFiles.length > 0) {
			addFiles(pFiles);
		} else {
			app.quit();
		}

		// All images processed? Remove file. If not, save list.
		if (uArray.length === 0) {
			fs.unlink(unFiles, (err) => {
				if (err) throw err;
			});
		} else {
			fs.writeFile(unFiles, JSON.stringify(uArray, null, '\t'), (err) => {
				if (err) console.log(err);
			});
		}

	}, false);

	// If files have been processed, display them
	if (fs.existsSync(jFiles)) {
		jsonDisplay();
	} else {
		document.getElementById('browse').style.display = 'block';
	}

	// If unprocessed images, continue processing them
	if (fs.existsSync(unFiles)) {
		fs.readFile(unFiles, (err, data) => {
			if (err) throw err;

			const unprocessedJson = JSON.parse(data);
			uArray = unprocessedJson;
			initAssets(unprocessedJson);
		});
	}

	// Send message to main process to load files
	document.getElementById('browse-files').addEventListener('click', () => {
		ipcRenderer.send('loadAssets');
	});
})();

// Displays assets once browse btn is clicked
ipcRenderer.on('getAssets', (event, filtered) => {
	document.getElementById('browse').style.display = 'none';

	uArray = filtered;
	initAssets(filtered);

});

// Process and append each asset
function initAssets(array) {
	for (let i = array.length; i-- > 0;) {
		process(array, i);

		// If at end of array, save json. Prevent overwritting. Use addFiles()
		if (i === 0) {
			if (fs.existsSync(jFiles)) {
				fs.readFile(jFiles, (err, data) => {
					if (err) throw err;

					const jsonFiles = JSON.parse(data),
						  newFiles = jsonFiles.concat(pFiles);

					fs.writeFile(jFiles, JSON.stringify(newFiles, null, '\t'), (err) => {
						if (err) throw err;
					});
				});
			} else {
				fs.writeFile(jFiles, JSON.stringify(pFiles), (err) => {
					if (err) console.log(err);
				});
			}
		}
	}
}

// Process Images
function process(image, count) {
	// Format path strings
	let src = image[count].path.replace(/\\/g,"/"),
		fileName = path.basename(image[count].path).replace(/\.[^.]+$/g,"");

	// Process image
	pImg.processImage(src, count).then((path) => {
		let formattedPath = path.replace(/\\/g,"/");

		// Push file info to array
		pFiles.push({file: formattedPath, name: fileName});

		// Filter out processed image from array
		uArray = uArray.filter(item => item.path != image[count].path);

		// Create html for images
		genHtml(fileName, formattedPath);

		console.log(uArray);
	});
};

// Displays processed files
function jsonDisplay() {
	let jsonFiles = [];

	fs.readFile(jFiles, (err, data) => {
		if (err) throw err;

		jsonFiles = JSON.parse(data);

		for (let i = 0; i < jsonFiles.length; i++) {
			genHtml(jsonFiles[i].name, jsonFiles[i].file);
		}
	});
}

// Create HTML elements and display images
function genHtml(fName, fPath) {
	// Create html elements
	let divImg = document.createElement('div'),
		imgName = document.createElement('p'),
		text = document.createTextNode(fName);

	// Create styles and add file path to div
	divImg.className = 'asset-img';
	imgName.className = 'asset-title';
	divImg.style.backgroundImage = 'url("' + fPath + '")';

	// Append elements to containers
	docFrag.appendChild(divImg);
	divImg.appendChild(imgName);
	imgName.appendChild(text);
	document.getElementById('asset-feed').appendChild(docFrag);
}

// Adds newly processed files to json file - Can use in initAssets()
function addFiles(array) {
	if (fs.existsSync(jFiles)) {
		fs.readFile(jFiles, (err, data) => {
			if (err) throw err;

			const jsonFiles = JSON.parse(data),
				  newFiles = jsonFiles.concat(array);

			fs.writeFile(jFiles, JSON.stringify(newFiles, null, '\t'), (err) => {
				if (err) throw err;

				app.quit();
			});
		});
	} else {
		fs.writeFile(jFiles, JSON.stringify(array, null, '\t'), (err) => {
			if (err) throw err;

			app.quit();
		});
	}
}<commit_msg>Removed console.log<commit_after>'use strict'

require("babel-core").transform("code");

const {ipcRenderer} = require('electron');
const {requireTaskPool} = require('electron-remote');
const {app} = require('electron').remote;

const remote = require('electron').remote,
	  fs = require('fs'),
	  path = require('path'),
	  pImg = requireTaskPool(require.resolve('./imgProcess')),
	  jFiles = path.join(app.getPath('userData'), 'files.json'),
	  unFiles = path.join(app.getPath('userData'), 'unprocessed.json');

let docFrag = document.createDocumentFragment(),
	pFiles = [],
	uArray = [];

// Create window controls and browse functionality
(function() {
	document.getElementById('min-btn').addEventListener('click', () => {
		remote.getCurrentWindow().minimize();
	}, false);

	document.getElementById('max-btn').addEventListener('click', () => {
		if (!remote.getCurrentWindow().isMaximized()) {
			remote.getCurrentWindow().maximize();
		} else {
			remote.getCurrentWindow().unmaximize();
		}
	}, false);

	document.getElementById('close-btn').addEventListener('click', () => {

		// Add processed images to files.json if app quit before finishing
		// Figure out a way to run an app.quit() after adding files. PROMISES!
		if (pFiles.length > 0) {
			addFiles(pFiles);
		} else {
			app.quit();
		}

		// All images processed? Remove file. If not, save list.
		if (uArray.length === 0) {
			fs.unlink(unFiles, (err) => {
				if (err) throw err;
			});
		} else {
			fs.writeFile(unFiles, JSON.stringify(uArray, null, '\t'), (err) => {
				if (err) console.log(err);
			});
		}

	}, false);

	// If files have been processed, display them
	if (fs.existsSync(jFiles)) {
		jsonDisplay();
	} else {
		document.getElementById('browse').style.display = 'block';
	}

	// If unprocessed images, continue processing them
	if (fs.existsSync(unFiles)) {
		fs.readFile(unFiles, (err, data) => {
			if (err) throw err;

			const unprocessedJson = JSON.parse(data);
			uArray = unprocessedJson;
			initAssets(unprocessedJson);
		});
	}

	// Send message to main process to load files
	document.getElementById('browse-files').addEventListener('click', () => {
		ipcRenderer.send('loadAssets');
	});
})();

// Displays assets once browse btn is clicked
ipcRenderer.on('getAssets', (event, filtered) => {
	document.getElementById('browse').style.display = 'none';

	uArray = filtered;
	initAssets(filtered);

});

// Process and append each asset
function initAssets(array) {
	for (let i = array.length; i-- > 0;) {
		process(array, i);

		// If at end of array, save json. Prevent overwritting. Use addFiles()
		if (i === 0) {
			if (fs.existsSync(jFiles)) {
				fs.readFile(jFiles, (err, data) => {
					if (err) throw err;

					const jsonFiles = JSON.parse(data),
						  newFiles = jsonFiles.concat(pFiles);

					fs.writeFile(jFiles, JSON.stringify(newFiles, null, '\t'), (err) => {
						if (err) throw err;
					});
				});
			} else {
				fs.writeFile(jFiles, JSON.stringify(pFiles), (err) => {
					if (err) console.log(err);
				});
			}
		}
	}
}

// Process Images
function process(image, count) {
	// Format path strings
	let src = image[count].path.replace(/\\/g,"/"),
		fileName = path.basename(image[count].path).replace(/\.[^.]+$/g,"");

	// Process image
	pImg.processImage(src, count).then((path) => {
		let formattedPath = path.replace(/\\/g,"/");

		// Push file info to array
		pFiles.push({file: formattedPath, name: fileName});

		// Filter out processed image from array
		uArray = uArray.filter(item => item.path != image[count].path);

		// Create html for images
		genHtml(fileName, formattedPath);
	});
};

// Displays processed files
function jsonDisplay() {
	let jsonFiles = [];

	fs.readFile(jFiles, (err, data) => {
		if (err) throw err;

		jsonFiles = JSON.parse(data);

		for (let i = 0; i < jsonFiles.length; i++) {
			genHtml(jsonFiles[i].name, jsonFiles[i].file);
		}
	});
}

// Create HTML elements and display images
function genHtml(fName, fPath) {
	// Create html elements
	let divImg = document.createElement('div'),
		imgName = document.createElement('p'),
		text = document.createTextNode(fName);

	// Create styles and add file path to div
	divImg.className = 'asset-img';
	imgName.className = 'asset-title';
	divImg.style.backgroundImage = 'url("' + fPath + '")';

	// Append elements to containers
	docFrag.appendChild(divImg);
	divImg.appendChild(imgName);
	imgName.appendChild(text);
	document.getElementById('asset-feed').appendChild(docFrag);
}

// Adds newly processed files to json file - Can use in initAssets()
function addFiles(array) {
	if (fs.existsSync(jFiles)) {
		fs.readFile(jFiles, (err, data) => {
			if (err) throw err;

			const jsonFiles = JSON.parse(data),
				  newFiles = jsonFiles.concat(array);

			fs.writeFile(jFiles, JSON.stringify(newFiles, null, '\t'), (err) => {
				if (err) throw err;

				app.quit();
			});
		});
	} else {
		fs.writeFile(jFiles, JSON.stringify(array, null, '\t'), (err) => {
			if (err) throw err;

			app.quit();
		});
	}
}<|endoftext|>


<commit_before>var fs = require('fs');
var config = require(process.env.HOME + '/.nodebncc/config.json');
var bncConfig = require(process.env.HOME + '/.nodebnc/config.json');
var _ = require('underscore');

var bncOptions = {
    tls: bncConfig.tls,
    key: fs.readFileSync(process.env.HOME + '/.nodebnc/nodebnc-key.pem'),
    cert: fs.readFileSync(process.env.HOME + '/.nodebnc/nodebnc-cert.pem'),
    ca: fs.readFileSync(process.env.HOME + '/.nodebnc/nodebnc-cert.pem'),
    rejectUnauthorized: bncConfig.rejectUnauthorized
};

var bncSocket = require('socket.io-client')((bncConfig.tls ? 'https://' : 'http://') + bncConfig.hostname + ':' + bncConfig.port, bncOptions);

var httpServer = require('http')
.createServer().listen(config.port, 'localhost');
var io = require('socket.io')(httpServer);

var ircChans = {};

var initChan = function(channel) {
    if(channel && !ircChans[channel]) {
        ircChans[channel] = {
            messages: [],
            nicks: []
        };
    }
};

var handleMessage = function(message) {
    console.log(message);
    initChan(message.channel);

    ircChans[message.channel].messages.push(message);
    io.sockets.in(message.channel).emit(message);
    console.log('got msg on ' + message.channel);
};

bncSocket.on('connect', function() {
    console.log('connected');
    bncSocket.emit('refreshState', {
        limit: config.backlog
    });
    bncSocket.on('messages', function(channels) {
        _.each(channels, function(channel) {
            _.each(channel.messages, function(message) {
                handleMessage(message);
            });
        });
    });
    bncSocket.on('nickList', function(data) {
        console.log('got nick list for ' + data.channel + ':');
        console.log(data.nickList);
    });
    bncSocket.on('message', handleMessage);
    bncSocket.on('bncErr', function(err) {
        console.log('error! ' + JSON.stringify(err, undefined, 4));
    });
});
<commit_msg>handle nicklists<commit_after>var fs = require('fs');
var config = require(process.env.HOME + '/.nodebncc/config.json');
var bncConfig = require(process.env.HOME + '/.nodebnc/config.json');
var _ = require('underscore');

var bncOptions = {
    tls: bncConfig.tls,
    key: fs.readFileSync(process.env.HOME + '/.nodebnc/nodebnc-key.pem'),
    cert: fs.readFileSync(process.env.HOME + '/.nodebnc/nodebnc-cert.pem'),
    ca: fs.readFileSync(process.env.HOME + '/.nodebnc/nodebnc-cert.pem'),
    rejectUnauthorized: bncConfig.rejectUnauthorized
};

var bncSocket = require('socket.io-client')((bncConfig.tls ? 'https://' : 'http://') + bncConfig.hostname + ':' + bncConfig.port, bncOptions);

var httpServer = require('http')
.createServer().listen(config.port, 'localhost');
var io = require('socket.io')(httpServer);

var ircChans = {};

var initChan = function(channel) {
    if(channel && !ircChans[channel]) {
        ircChans[channel] = {
            messages: [],
            nicks: []
        };
    }
};

var handleMessage = function(message) {
    console.log(message);
    initChan(message.channel);

    ircChans[message.channel].messages.push(message);
    io.sockets.in(message.channel).emit('message', message);
    console.log('got msg on ' + message.channel);
};

var handleNickList = function(channel, nickList) {
    console.log('got nick list for ' + channel + ':');
    console.log(nickList);
    initChan(channel);

    ircChans[channel].nicks = nickList;
    io.sockets.in(channel).emit('nickList', [channel, nickList]);
};

bncSocket.on('connect', function() {
    console.log('connected');
    bncSocket.emit('refreshState', {
        limit: config.backlog
    });
    bncSocket.on('messages', function(channels) {
        _.each(channels, function(channel) {
            _.each(channel.messages, function(message) {
                handleMessage(message);
            });
        });
    });
    bncSocket.on('nickLists', function(channels) {
        _.each(channels, function(nickList, channel) {
            handleNickList(channel, nickList);
        });
    });
    bncSocket.on('nickList', function(nickList) {
        handleNickList(channel, nickList);
    });
    bncSocket.on('message', handleMessage);
    bncSocket.on('bncErr', function(err) {
        console.log('error! ' + JSON.stringify(err, undefined, 4));
    });
});
<|endoftext|>


<commit_before>(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.capitaljs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
/**
 * amortization table calculations
 * ===============================
 * calculates the monthly payment
 * calculates remaining loan balance
 * calculates sum of interest payments
 * calculates sum of principal payments
 * @param {number} amount
 * @param {number} rate
 * @param {number} totalTerm
 * @param {number} amortizeTerm
 * @returns {object}
 */
var amortizationCalc = function(amount, rate, totalTerm, amortizeTerm) {
  var periodInt,
      monthlyPayment,
      summedInterest = 0,
      summedPrincipal = 0,
      monthlyIntPaid,
      monthlyPrincPaid,
      summedAmortize = {};

  // Calculate monthly interest rate and monthly payment
  periodInt = (rate / 12) / 100;
  monthlyPayment = amount * (periodInt / (1 - Math.pow(1 + periodInt, -(totalTerm))));
  // If zero or NaN is returned (i.e. if the rate is 0) calculate the payment without interest
  monthlyPayment = monthlyPayment || amount / totalTerm;

  // Calculate the interest, principal, and remaining balance for each period
  var i = 0;
  while( i < amortizeTerm) {
    monthlyIntPaid = amount * periodInt;
    monthlyPrincPaid = monthlyPayment - monthlyIntPaid;
    summedInterest = summedInterest + monthlyIntPaid;
    summedPrincipal = summedPrincipal + monthlyPrincPaid;
    amount = amount - monthlyPrincPaid;
    i += 1;
  }

  summedAmortize.interest = summedInterest;
  summedAmortize.principal = summedPrincipal;
  summedAmortize.balance = amount;
  summedAmortize.payment = monthlyPayment;

  return summedAmortize;

};

/**
 * Throw an error if a string or number below 0 is passed
 * @param {object}
 * @returns {object}
 */
var errorCheck = function(opts) {
  for (var key in opts) {
    if (opts.hasOwnProperty(key)) {
      if (typeof opts[key] === 'undefined' || isNaN(parseFloat(opts[key])) || opts[key] < 0) {
        throw new Error('Loan ' + key + ' must be a non-negative value.');
      }
    }
  }
};

/**
 * Round values to two decimal places
 * @param {object}
 * @returns {object}
 */
var roundNum = function(numObj) {
  var tmp = {};
  for (var property in numObj) {
    tmp[property] = numObj[property];
    tmp[property + 'Round'] = (Math.round(numObj[property] * 100) / 100).toFixed(2);
  }
  return tmp;
};

/**
 * Pass values and return output
 * @param {object} amount, rate, totalTerm, amortizeTerm
 * @example amortize({amount: 180000, rate: 4.25, totalTerm: 360, amortizeTerm: 60})
 * @returns {object}
 */
var amortize = function(opts) {
  errorCheck(opts);
  var amortized = amortizationCalc(opts.amount, opts.rate, opts.totalTerm, opts.amortizeTerm);
  return roundNum(amortized);
};

module.exports = amortize;
},{}],2:[function(_dereq_,module,exports){
"use strict";
var amortize = _dereq_('amortize'),
    enforcePositive = _dereq_('./utils/enforce/number/positive'),
    sumArray = _dereq_('./utils/sumArray');
function amortization(opts) {
  var $__1;
  var $__0 = opts,
      amount = $__0.amount,
      rate = $__0.rate,
      totalTerm = $__0.totalTerm,
      amortizeTerm = ($__1 = $__0.amortizeTerm) === void 0 ? true : $__1,
      result = {};
  enforcePositive(opts);
  if (!amount || !rate || !totalTerm || !amortizeTerm) {
    throw new Error('Amount, rate, totalTerm, and amortizeTerm are required and must be non-negative.');
  }
  result = amortize(opts);
  return result;
}
module.exports = amortization;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/amortization.js
},{"./utils/enforce/number/positive":10,"./utils/sumArray":12,"amortize":1}],3:[function(_dereq_,module,exports){
"use strict";
var enforcePositive = _dereq_('./utils/enforce/number/positive'),
    sumArray = _dereq_('./utils/sumArray');
function arrayCheck(val) {
  if (val.constructor === Array) {
    val = sumArray(val);
  }
  return val;
}
function cashFlow(opts) {
  var $__1;
  var $__0 = opts,
      income = $__0.income,
      expenses = ($__1 = $__0.expenses) === void 0 ? true : $__1,
      result = {};
  enforcePositive(opts);
  if (!income || !expenses) {
    throw new Error('Income and expenses are required and must be non-negative.');
  }
  result.income = arrayCheck(income);
  result.expenses = arrayCheck(expenses);
  result.cash = result.income - result.expenses;
  return result;
}
module.exports = cashFlow;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/cashFlow.js
},{"./utils/enforce/number/positive":10,"./utils/sumArray":12}],4:[function(_dereq_,module,exports){
"use strict";
var enforceNumber = _dereq_('./utils/enforce/number');
function compoundAnnualGrowthRate(opts) {
  var $__0 = opts,
      startValue = $__0.startValue,
      endValue = $__0.endValue,
      years = $__0.years,
      result = {};
  enforceNumber(opts);
  if (!startValue || !endValue || !years) {
    throw new Error('Start value, end value and years are required and must be numbers.');
  }
  result.raw = Math.pow(endValue / startValue, 1 / years) - 1;
  result.rounded = Math.round(result.raw * 1000) / 1000;
  result.percent = result.rounded * 100;
  return result;
}
module.exports = compoundAnnualGrowthRate;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/compoundAnnualGrowthRate.js
},{"./utils/enforce/number":9}],5:[function(_dereq_,module,exports){
"use strict";
module.exports = {
  'interest': _dereq_('./interest'),
  'cashFlow': _dereq_('./cashFlow'),
  'compoundAnnualGrowthRate': _dereq_('./compoundAnnualGrowthRate'),
  'inflationAdjustedReturn': _dereq_('./inflationAdjustedReturn'),
  'amortization': _dereq_('./amortization'),
  'returnOnInvestment': _dereq_('./returnOnInvestment')
};

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/index.js
},{"./amortization":2,"./cashFlow":3,"./compoundAnnualGrowthRate":4,"./inflationAdjustedReturn":6,"./interest":7,"./returnOnInvestment":8}],6:[function(_dereq_,module,exports){
"use strict";
function inflationAdjustedReturn(opts) {
  var $__1;
  var $__0 = opts,
      investmentReturn = $__0.investmentReturn,
      inflationRate = ($__1 = $__0.inflationRate) === void 0 ? true : $__1,
      realReturn;
  if (!investmentReturn || !inflationRate) {
    throw new Error('Income and expenses are required and must be non-negative.');
  }
  realReturn = ((1 + investmentReturn) / (1 + inflationRate) - 1) * 100;
  realReturn = (Math.round(realReturn * 100) / 100);
  return realReturn;
}
module.exports = inflationAdjustedReturn;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/inflationAdjustedReturn.js
},{}],7:[function(_dereq_,module,exports){
"use strict";
var enforcePositive = _dereq_('./utils/enforce/number/positive');
function interest(opts) {
  var $__0 = opts,
      principal = $__0.principal,
      rate = $__0.rate,
      periods = $__0.periods,
      compoundings = $__0.compoundings,
      result = {};
  delete opts.compounding;
  delete opts.compoundingsPerPeriod;
  enforcePositive(opts);
  if (!principal || !rate || !periods) {
    throw new Error('Principal, rate and number of periods are required and must be non-negative.');
  }
  if (compoundings) {
    result.total = Math.pow((1 + ((rate / 100) / compoundings)), compoundings * periods) * principal;
    result.total = Math.round(result.total * 100) / 100;
  } else {
    result.total = principal * (1 + ((rate / 100) * periods));
  }
  result.interest = result.total - principal;
  return result;
}
module.exports = interest;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/interest.js
},{"./utils/enforce/number/positive":10}],8:[function(_dereq_,module,exports){
"use strict";
var enforceNumber = _dereq_('./utils/enforce/number');
function returnOnInvestment(opts) {
  var $__0 = opts,
      earnings = $__0.earnings,
      initialInvestment = $__0.initialInvestment,
      result = {};
  enforceNumber(opts);
  if (!earnings || !initialInvestment) {
    throw new Error('Earnings and initial investment are required and must be numbers.');
  }
  result.raw = (earnings - initialInvestment) / initialInvestment;
  result.rounded = Math.round(result.raw * 10000) / 10000;
  result.percent = result.rounded * 100;
  return result;
}
module.exports = returnOnInvestment;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/returnOnInvestment.js
},{"./utils/enforce/number":9}],9:[function(_dereq_,module,exports){
"use strict";
function enforceNumber(opts) {
  for (var key in opts) {
    if (opts.hasOwnProperty(key)) {
      if (typeof opts[key] === 'undefined' || isNaN(parseFloat(opts[key]))) {
        throw new Error(key + ' must be a number.');
      }
    }
  }
}
;
module.exports = enforceNumber;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/utils/enforce/number/index.js
},{}],10:[function(_dereq_,module,exports){
"use strict";
var processOpts = _dereq_('../../processOpts');
function check(key, val) {
  if (typeof val === 'undefined' || isNaN(parseFloat(val)) || val < 0) {
    throw new Error(key + ' must be a non-negative value.');
  }
}
function enforceNonNegativeNumber(opts) {
  processOpts(opts, check);
}
;
module.exports = enforceNonNegativeNumber;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/utils/enforce/number/positive.js
},{"../../processOpts":11}],11:[function(_dereq_,module,exports){
"use strict";
function processOpts(opts, cb) {
  if (opts === Object(opts) && Object.prototype.toString.call(opts) !== '[object Array]') {
    for (var key in opts) {
      if (opts.hasOwnProperty(key)) {
        cb(key, opts[key]);
      }
    }
  } else if (opts instanceof Array) {
    for (var i = 0; i < opts.length; i++) {
      cb('All params', opts[i]);
    }
  } else {
    cb('All params', opts);
  }
}
;
module.exports = processOpts;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/utils/processOpts.js
},{}],12:[function(_dereq_,module,exports){
"use strict";
function sumArray(arr) {
  var total = 0;
  for (var i = 0; i < arr.length; i++) {
    total += arr[i];
  }
  return total;
}
module.exports = sumArray;

//# sourceURL=/Users/contolinic/Sites/capitaljs/capitaljs/src/utils/sumArray.js
},{}]},{},[5])(5)
});<commit_msg>rm compiled code<commit_after><|endoftext|>


<commit_before>var bot = require("./lib/bot.js");
var Hapi = require('hapi');

if (process.env.ARIELENV === "dev") {
  opts = {
    port: 8000
  };
} else {
  opts = {
    port: 2121
  };
}

// Create a server with a host and port
var server = new Hapi.Server();
server.connection({
  host: 'localhost',
  port: opts.port
});

// Add the route
server.route([
  {
    method: 'GET',
    path:'/',
    handler: {
      file: function (request) {
        return "public/html/user.html";
      }
    }
  },
  {
    method: 'GET',
    path:'/{filename}',
    handler: {
      file: function (request) {
        return "public/html/"+request.params.filename;
      }
    }
  },
  {
    method: 'GET',
    path:'/js/{filename}',
    handler: {
      file: function (request) {
        return "public/js/"+request.params.filename;
      }
    }
  },
  {
    method: 'GET',
    path:'/css/{filename}',
    handler: {
      file: function (request) {
        return "public/css/"+request.params.filename;
      }
    }
  }
]);

// Start the server
server.start();

var io = require('socket.io')(server.listener);

io.on('connection', function (socket) {
  socket.on('newUser', function () {
    console.log("Hi New User");
  });
  socket.on("toggleLED", function() {
    bot.toggle();
    console.log("Toggle LED");
  });
});

console.log("Server running on port " + opts.port);
<commit_msg>Change ports<commit_after>var bot = require("./lib/bot.js");
var Hapi = require('hapi');

if (process.env.ARIELENV === "dev") {
  opts = {
    port: 8080
  };
} else {
  opts = {
    port: 80
  };
}

// Create a server with a host and port
var server = new Hapi.Server();
server.connection({
  port: opts.port
});

// Add the route
server.route([
  {
    method: 'GET',
    path:'/',
    handler: {
      file: function (request) {
        return "public/html/user.html";
      }
    }
  },
  {
    method: 'GET',
    path:'/{filename}',
    handler: {
      file: function (request) {
        return "public/html/"+request.params.filename;
      }
    }
  },
  {
    method: 'GET',
    path:'/js/{filename}',
    handler: {
      file: function (request) {
        return "public/js/"+request.params.filename;
      }
    }
  },
  {
    method: 'GET',
    path:'/css/{filename}',
    handler: {
      file: function (request) {
        return "public/css/"+request.params.filename;
      }
    }
  }
]);

// Start the server
server.start();

var io = require('socket.io')(server.listener);

io.on('connection', function (socket) {
  socket.on('newUser', function () {
    console.log("Hi New User");
  });
  socket.on("toggleLED", function() {
    bot.toggle();
    console.log("Toggle LED");
  });
});

console.log("Server running on port " + opts.port);
<|endoftext|>