<commit_before>"use strict";
const path = require("path");
const Busboy = require("busboy");
const hasha = require("hasha");

const ExpressFormPost = function(user_options = {}) {
	if(!(this instanceof ExpressFormPost)) return new ExpressFormPost(user_options);

	// validateFile
	if(user_options.validateFile) {
		if(typeof user_options.validateFile != "function") throw new Error("option 'validateFile' must be a function.");
	} else {
		user_options.validateFile = (handlePromise) => handlePromise();
	}

	/*
	 * validateBody validates the req.body before sending off files to the store
	 * if validateBody is set in any way, the file buffers will be sent to the store after the request has been validated
	 * This means that file_contents.end() only triggers after the "end" event is emitted
	 */
	if(user_options.validateBody) {
		if(typeof user_options.validateBody != "function") {
			throw new Error("option validateBody must be a function.");
		}
	} else {
		user_options.validateBody = (handlePromise) => handlePromise();
	}

	// max file size
	if(user_options.maxfileSize) {
		if(!Number.isInteger(user_options.maxfileSize)) {
			throw new Error("option 'maxfileSize' must be an integer (Measured in bytes).");
		}
	}

	// Available storage methods
	if(!["disk", "aws-s3", "dropbox"].includes(user_options.store)) {
		if(user_options.store == undefined) {
			user_options.store = "disk";
		} else {
			throw new Error("storage " + user_options.store + " is not supported by express-form-post");
		}
	}

	// Setting default directory based on store
	user_options.directory == undefined ? user_options.store == "disk" ? (
		user_options.directory = path.join(module.parent.filename, "..")
	) : user_options.directory = "" : "";

	// filename options setup
	if(typeof user_options.filename == "function") {
		let customFileMethod = user_options.filename;
		user_options.filename = function(originalname, fieldname, mimetype) {
			let customName = customFileMethod(originalname, fieldname, mimetype);
			if(customName == undefined || customName == "") {
				return originalname; // returning the original name that is being uploaded
			}
			return customName;
		};

	} else {
		switch(user_options.filename) {
		case undefined:
		case "":
			user_options.filename = (originalname) => { return hasha(originalname); };
			break;
		default:
			var user_input = user_options.filename; // Closures are awesome
			user_options.filename = () => { return user_input; };
		}
	}

	this.options = {
		store: user_options.store,
		directory: user_options.directory,
		filename: user_options.filename,
		maxfileSize: user_options.maxfileSize,
		minfileSize: user_options.minfileSize || 0,
		validateFile: user_options.validateFile,
		validateBody: user_options.validateBody,
		api: user_options.api
	};

	this.storeMethod = require(path.join(__dirname, "lib", this.options.store));

	// set up abi objects here so we won't have to recreate upon sending buffer to store handler
	switch(this.options.store){
	case "aws-s3":{
		let aws = require("aws-sdk");
		aws.config.update({
			accessKeyId: this.options.api.accessKeyId,
			secretAccessKey: this.options.api.secretAccessKey,
		});
		this.apiObject = new aws.S3();
		break;
	}
	case "dropbox":{
		let Dropbox = require("dropbox");
		this.apiObject = new Dropbox({
			accessToken: this.options.api.accessToken,
			clientId: this.options.api.clientId,
			selectUser: this.options.api.selectUser,
		});
		break;
	}
	default:
		this.apiObject = {}; // apiObject does not init on disk
	}
};

ExpressFormPost.prototype._attachListeners = function(busboy, req) {

	busboy.on("file", (fieldname, file, originalname, encoding, mimetype) => {
		// emit 'end' event on file skip attaching listeners
		if(originalname == "" || req.efp._finished || req.efp._data[fieldname] != undefined) return file.resume();

		// Busboy emits limit event before my file listeners can reach it
		file.on("limit", () => {
			!req.efp._finished ? (
				this.removeUploads(),
				this.handleError(new Error("File limit reached on file"))
			): "";
		});

		file.on("end", () => {
			if(!req.efp._finished && this.options.minfileSize > req.efp._data[fieldname]) {
				this.removeUploads();
				this.handleError(new Error("Uploaded file was smaller than minfileSize"));
			}
		});

		new Promise((resolve, reject) => {
			// handlePromise is cb in function declaration
			const handlePromise = (valid) => {
				valid == false ? reject((new Error("Validation error by custom validateFile function"))) : (
					resolve()
				);
			};
			this.options.validateFile(handlePromise, fieldname, mimetype);
		})
		.then(() => {
			// user may use filename function but incorrectly return nothing. no warning supplied. defaults to hash
			let save_filename = this.options.filename(originalname, fieldname, mimetype);
			typeof save_filename == "string" && save_filename.length > 0 ? "" : save_filename = hasha(originalname);
			save_filename.includes("/") ? (
				this.options.directory = path.join(this.options.directory, save_filename, ".."),
				save_filename = path.basename(path.resolve(...(save_filename.split("/"))))
			): "";

			let uploadInfo = {
				directory: this.options.directory,
				filename: save_filename,
				mimetype: mimetype,
				fieldname: fieldname,
				file: file,
				encoding: encoding,
				api: this.options.api,
				apiObject: this.apiObject
			};

			// init duplex stream (read/writable) or concat-stream depending on store method
			const file_contents = this.storeMethod(uploadInfo, req, this.finished, this.handleError);
			req.efp.streams.push(file_contents);
			req.efp._data[fieldname] = 0; // initialize the stream size tracker

			file.on("data", (data) => {
				if(!req.efp._finished) {
					req.efp._data[fieldname] += data.length;
					file_contents.write(data);
				}
			});

		})
		.catch((err) => {
			this.removeUploads();
			this.handleError(err);
			return file.resume(); // emit 'end' event on file for busboy 'finish' prevents infinite piping for req
		});
	});

	busboy.on("field", (fieldname, val, fieldnameTruncated, valTruncated) => {
		// Possibly should add some handler for if a certain value was truncated
		!req.efp._finished && !valTruncated && !fieldnameTruncated ? req.body[fieldname] = val : "";
	});
	busboy.on("finish", () => {
		req.efp.busboy._finished = true;
		if(req.efp._finished) return;
		new Promise((resolve, reject) => {
			const handlePromise = (flag) => {
				flag == false ? reject(new Error("Validation failed on validateBody function")) : resolve();
			};
			this.options.validateBody(handlePromise, req.body);
		})
		.then(() => {
			for(var key in req.efp.streams) {
				req.efp.streams[key].end();
			}
			return this.finished(); // If there was no files this triggers properly, otherwise it is called when ending streams
		})
		.catch((err) => {
			this.removeUploads();
			return this.handleError(err);
		});
	});
};

ExpressFormPost.prototype._fileHandler = function(req, res, cb) {
	if(req.method == "POST") {
		if(req._body) return cb();
		/*
		 * _validFile defaults to true and becomes false if the file being uploaded is not valid
		 * _finished is false by default and set to true if efp has "finished". Usually this just means that
		 * the next middleware has been called already and further calls to finished and handleError does nothing
		 * efp.busboy._finished is false by default and true if busboy is done parsing
		 * _data tracks if a file field has transmitted data (or has contents).
		 * ^^ this is set to avoid errors with concat-stream empty buffers
		 */
		req.efp = { _validFile: true, _finished: false, _data: {}, busboy: { _finished: false }, streams: []};
		req.body = {};
		req._body = true; // prevent multiple multipart middleware and body-parser from colliding
		req.files = {};

		/*
		 * In middleware, this.finished passes on to next middleware
		 * Validation checking in this.finished because of upload function cb not next param in middleware
		 * In upload function, this.finished will be the callback with an err parameter. (err be undefined)
		 * this.finished will be called when finished with parsing the request to pass on to the cb action
		 * buffers array holds file contents that should be sent to the store if the body is valid
		 */
		this.next = cb; // for middleware usage
		this.finished = function(err) {
			if(req.efp._finished) return;
			if(err) {
				req.efp._finished = true;
				return cb(err); // only gets called when upload is being used and as handleError
			}
			if(Object.keys(req.files).length == Object.keys(req.efp._data).length && req.efp.busboy._finished) {
				// all files that were sent to the store have been uploaded and busboy is done parsing
				req.efp._finished = true;
				return cb();
			}
		};

		// make sure this is called before handleError call
		this.removeUploads = function() {
			if(req.efp._finished) return;
			req.body = {};
			for(var key in req.efp.streams) {
				req.efp.streams[key].emit("destroy");
			}
		};

		/*
		 * A call to this.handleError will nullify any subsequent calls to this.finished and this.handleError
		 * 1st expr resolves to middleware and 2nd to upload
		 */
		this.handleError ? (
			// User input based handle Error assignment - handleError could resolve to something not
			// a function if the user input is incorrect. ignore if so
			typeof this.middleware.handleError == "function" ? (
				this.handleError = (err) => {
					!req.efp._finished? (
						req.efp._finished = true,
						this.middleware.handleError(err),
						this.next()
					) : "";
				}
			) : (
				this.handleError = () => {
					!req.efp._finished ? (
						req.efp._finished = true,
						this.next()
					): "";
				}
			)
		) : this.handleError = this.finished;

		try {
			var busboy = new Busboy({
				headers: req.headers,
				limits: {
					fileSize: this.options.maxfileSize
				}
			});
			this._attachListeners(busboy, req);
			req.pipe(busboy);
		} catch(err) {
			this.handleError(err);
		}
	} else {
		return cb();
	}
};

ExpressFormPost.prototype.fields = function() {
	return require("./lib/fields").bind(this);
};

ExpressFormPost.prototype.middleware = function(handleError = undefined) {
	this.middleware.handleError = handleError; // the function to be called inside handleError
	this.handleError = () => {}; // empty anon function to be reassigned in fileHandler
	/*
	 * fileHandler will be called in app.use as (req, res, cb)
	 * binding this to the return value because when it is used in the express middleware _filehandler loses this context
	 * the value of _fileHandler the function is being used to call rather than the function itself
	 */
	return this._fileHandler.bind(this);
};

// Upload function to be used within routes. handleError set as callback as well and can be check with if (err)
ExpressFormPost.prototype.upload = function(req, res, cb = () => {}) {
	typeof cb == "function" ? "" : cb = () => {}; // prevent user failure
	// reassign in fileHandler
	this.handleError = undefined;
	// cb is cb in fileHandler param
	this._fileHandler(req, res, cb);
};

module.exports = ExpressFormPost;<commit_msg>modify main module to support Promise oriented architecture<commit_after>"use strict";
const path = require("path");
const Busboy = require("busboy");
const hasha = require("hasha");

const ExpressFormPost = function(user_options = {}) {
	if(!(this instanceof ExpressFormPost)) return new ExpressFormPost(user_options);

	// validateFile
	if(user_options.validateFile) {
		if(typeof user_options.validateFile != "function") throw new Error("option 'validateFile' must be a function.");
	} else {
		user_options.validateFile = (handlePromise) => handlePromise();
	}

	/*
	 * validateBody validates the req.body before sending off files to the store
	 * if validateBody is set in any way, the file buffers will be sent to the store after the request has been validated
	 * This means that file_contents.end() only triggers after the "end" event is emitted
	 */
	if(user_options.validateBody) {
		if(typeof user_options.validateBody != "function") {
			throw new Error("option validateBody must be a function.");
		}
	} else {
		user_options.validateBody = (handlePromise) => handlePromise();
	}

	// max file size
	if(user_options.maxfileSize) {
		if(!Number.isInteger(user_options.maxfileSize)) {
			throw new Error("option 'maxfileSize' must be an integer (Measured in bytes).");
		}
	}

	// Available storage methods
	if(!["disk", "aws-s3", "dropbox"].includes(user_options.store)) {
		if(user_options.store == undefined) {
			user_options.store = "disk";
		} else {
			throw new Error("storage " + user_options.store + " is not supported by express-form-post");
		}
	}

	// Setting default directory based on store
	user_options.directory == undefined ? user_options.store == "disk" ? (
		user_options.directory = path.join(module.parent.filename, "..")
	) : user_options.directory = "" : "";

	// filename options setup
	if(typeof user_options.filename == "function") {
		let customFileMethod = user_options.filename;
		user_options.filename = function(originalname, fieldname, mimetype) {
			let customName = customFileMethod(originalname, fieldname, mimetype);
			if(customName == undefined || customName == "") {
				return originalname; // returning the original name that is being uploaded
			}
			return customName;
		};

	} else {
		switch(user_options.filename) {
		case undefined:
		case "":
			user_options.filename = (originalname) => { return hasha(originalname); };
			break;
		default:
			var user_input = user_options.filename; // Closures are awesome
			user_options.filename = () => { return user_input; };
		}
	}

	this.options = {
		store: user_options.store,
		directory: user_options.directory,
		filename: user_options.filename,
		maxfileSize: user_options.maxfileSize,
		minfileSize: user_options.minfileSize || 0,
		validateFile: user_options.validateFile,
		validateBody: user_options.validateBody,
		api: user_options.api
	};

	this.storeMethod = require(path.join(__dirname, "lib", this.options.store));

	// set up abi objects here so we won't have to recreate upon sending buffer to store handler
	switch(this.options.store){
	case "aws-s3":{
		let aws = require("aws-sdk");
		aws.config.update({
			accessKeyId: this.options.api.accessKeyId,
			secretAccessKey: this.options.api.secretAccessKey,
		});
		this.apiObject = new aws.S3();
		break;
	}
	case "dropbox":{
		let Dropbox = require("dropbox");
		this.apiObject = new Dropbox({
			accessToken: this.options.api.accessToken,
			clientId: this.options.api.clientId,
			selectUser: this.options.api.selectUser,
		});
		break;
	}
	default:
		this.apiObject = {}; // apiObject does not init on disk
	}
};

ExpressFormPost.prototype._attachListeners = function(busboy, req) {

	busboy.on("file", (fieldname, file, originalname, encoding, mimetype) => {
		// emit 'end' event on file skip attaching listeners
		if(originalname == "" || req.efp._finished || req.efp._data[fieldname] != undefined) return file.resume();

		// Busboy emits limit event before my file listeners can reach it
		file.on("limit", () => {
			!req.efp._finished ? (
				this.removeUploads(),
				this.handleError(new Error("File limit reached on file"))
			): "";
		});

		file.on("end", () => {
			if(!req.efp._finished && this.options.minfileSize > req.efp._data[fieldname]) {
				this.removeUploads();
				this.handleError(new Error("Uploaded file was smaller than minfileSize"));
			}
		});

		new Promise((resolve, reject) => {
			// handlePromise is cb in function declaration
			const handlePromise = (valid) => {
				valid == false ? reject((new Error("Validation error by custom validateFile function"))) : (
					resolve()
				);
			};
			this.options.validateFile(handlePromise, fieldname, mimetype);
		})
		.then(() => {
			// user may use filename function but incorrectly return nothing. no warning supplied. defaults to hash
			let save_filename = this.options.filename(originalname, fieldname, mimetype);
			typeof save_filename == "string" && save_filename.length > 0 ? "" : save_filename = hasha(originalname);
			save_filename.includes("/") ? (
				this.options.directory = path.join(this.options.directory, save_filename, ".."),
				save_filename = path.basename(path.resolve(...(save_filename.split("/"))))
			): "";

			let uploadInfo = {
				directory: this.options.directory,
				filename: save_filename,
				mimetype: mimetype,
				fieldname: fieldname,
				file: file,
				encoding: encoding,
				api: this.options.api,
				apiObject: this.apiObject
			};

			// init duplex stream (read/writable) or concat-stream depending on store method
			this.storeMethod(uploadInfo, req, this.finished, this.handleError)
			.then((file_contents) => {
				req.efp.streams.push(file_contents);
				req.efp._data[fieldname] = 0; // initialize the stream size tracker

				file.on("data", (data) => {
					if(!req.efp._finished) {
						req.efp._data[fieldname] += data.length;
						file_contents.write(data);
					}
				});
			})
			.catch((err) => {
				this.handleError(err);
			})

		})
		.catch((err) => {
			this.removeUploads();
			this.handleError(err);
			return file.resume(); // emit 'end' event on file for busboy 'finish' prevents infinite piping for req
		});
	});

	busboy.on("field", (fieldname, val, fieldnameTruncated, valTruncated) => {
		// Possibly should add some handler for if a certain value was truncated
		!req.efp._finished && !valTruncated && !fieldnameTruncated ? req.body[fieldname] = val : "";
	});
	busboy.on("finish", () => {
		req.efp.busboy._finished = true;
		if(req.efp._finished) return;
		new Promise((resolve, reject) => {
			const handlePromise = (flag) => {
				flag == false ? reject(new Error("Validation failed on validateBody function")) : resolve();
			};
			this.options.validateBody(handlePromise, req.body);
		})
		.then(() => {
			for(var key in req.efp.streams) {
				req.efp.streams[key].end();
			}
			return this.finished(); // If there was no files this triggers properly, otherwise it is called when ending streams
		})
		.catch((err) => {
			this.removeUploads();
			return this.handleError(err);
		});
	});
};

ExpressFormPost.prototype._fileHandler = function(req, res, cb) {
	if(req.method == "POST") {
		if(req._body) return cb();
		/*
		 * _validFile defaults to true and becomes false if the file being uploaded is not valid
		 * _finished is false by default and set to true if efp has "finished". Usually this just means that
		 * the next middleware has been called already and further calls to finished and handleError does nothing
		 * efp.busboy._finished is false by default and true if busboy is done parsing
		 * _data tracks if a file field has transmitted data (or has contents).
		 * ^^ this is set to avoid errors with concat-stream empty buffers
		 */
		req.efp = { _validFile: true, _finished: false, _data: {}, busboy: { _finished: false }, streams: []};
		req.body = {};
		req._body = true; // prevent multiple multipart middleware and body-parser from colliding
		req.files = {};

		/*
		 * In middleware, this.finished passes on to next middleware
		 * Validation checking in this.finished because of upload function cb not next param in middleware
		 * In upload function, this.finished will be the callback with an err parameter. (err be undefined)
		 * this.finished will be called when finished with parsing the request to pass on to the cb action
		 * buffers array holds file contents that should be sent to the store if the body is valid
		 */
		this.next = cb; // for middleware usage
		this.finished = function(err) {
			if(req.efp._finished) return;
			if(err) {
				req.efp._finished = true;
				return cb(err); // only gets called when upload is being used and as handleError
			}
			if(Object.keys(req.files).length == Object.keys(req.efp._data).length && req.efp.busboy._finished) {
				// all files that were sent to the store have been uploaded and busboy is done parsing
				req.efp._finished = true;
				return cb();
			}
		};

		// make sure this is called before handleError call
		this.removeUploads = function() {
			if(req.efp._finished) return;
			req.body = {};
			for(var key in req.efp.streams) {
				req.efp.streams[key].emit("destroy");
			}
		};

		/*
		 * A call to this.handleError will nullify any subsequent calls to this.finished and this.handleError
		 * 1st expr resolves to middleware and 2nd to upload
		 */
		this.handleError ? (
			// User input based handle Error assignment - handleError could resolve to something not
			// a function if the user input is incorrect. ignore if so
			typeof this.middleware.handleError == "function" ? (
				this.handleError = (err) => {
					!req.efp._finished? (
						req.efp._finished = true,
						this.middleware.handleError(err),
						this.next()
					) : "";
				}
			) : (
				this.handleError = () => {
					!req.efp._finished ? (
						req.efp._finished = true,
						this.next()
					): "";
				}
			)
		) : this.handleError = this.finished;

		try {
			var busboy = new Busboy({
				headers: req.headers,
				limits: {
					fileSize: this.options.maxfileSize
				}
			});
			this._attachListeners(busboy, req);
			req.pipe(busboy);
		} catch(err) {
			this.handleError(err);
		}
	} else {
		return cb();
	}
};

ExpressFormPost.prototype.fields = function() {
	return require("./lib/fields").bind(this);
};

ExpressFormPost.prototype.middleware = function(handleError = undefined) {
	this.middleware.handleError = handleError; // the function to be called inside handleError
	this.handleError = () => {}; // empty anon function to be reassigned in fileHandler
	/*
	 * fileHandler will be called in app.use as (req, res, cb)
	 * binding this to the return value because when it is used in the express middleware _filehandler loses this context
	 * the value of _fileHandler the function is being used to call rather than the function itself
	 */
	return this._fileHandler.bind(this);
};

// Upload function to be used within routes. handleError set as callback as well and can be check with if (err)
ExpressFormPost.prototype.upload = function(req, res, cb = () => {}) {
	typeof cb == "function" ? "" : cb = () => {}; // prevent user failure
	// reassign in fileHandler
	this.handleError = undefined;
	// cb is cb in fileHandler param
	this._fileHandler(req, res, cb);
};

module.exports = ExpressFormPost;<|endoftext|>


<commit_before>'use strict';

/**
 * Stringify/parse functions that don't operate
 * recursively, so they avoid call stack exceeded
 * errors.
 *
 * These don't implement the full JSON spec.
 * They just do enough to parse our rev tree objects,
 * which are pretty predictable.
 */
exports.stringify = function stringify(input) {
  var queue = [];
  queue.push({obj: input});

  var res = '';
  var next;
  while ((next = queue.pop())) {
    var obj = next.obj;
    var prefix = next.prefix || '';
    var val = next.val || '';
    res += prefix;
    if (val) {
      res += val;
    } else if (typeof obj !== 'object') {
      res += typeof obj === 'undefined' ? null : JSON.stringify(obj);
    } else if (obj === null) {
      res += 'null';
    } else if (Array.isArray(obj)) {
      queue.push({val: ']'});
      for (var i = obj.length - 1; i >= 0; i--) {
        var arrayPrefix = i === 0 ? '' : ',';
        queue.push({obj: obj[i], prefix: arrayPrefix});
      }
      queue.push({val: '['});
    } else { // object
      var keys = [];
      for (var k in obj) {
        if (obj.hasOwnProperty(k)) {
          keys.push(k);
        }
      }
      queue.push({val: '}'});
      for (var ii = keys.length - 1; ii >= 0; ii--) {
        var key = keys[ii];
        var value = obj[key];
        var objPrefix = (ii > 0 ? ',' : '');
        objPrefix += JSON.stringify(key) + ':';
        queue.push({obj: value, prefix: objPrefix});
      }
      queue.push({val: '{'});
    }
  }
  return res;
};

// Convenience function for the parse function.
// This pop function is basically copied from
// pouchCollate.parseIndexableString
function pop(obj, stack, metaStack) {
  if (metaStack.length) {
    var lastMetaElement = metaStack[metaStack.length - 1];
    if (obj === lastMetaElement.element) {
      // popping a meta-element, e.g. an object whose value is another object
      metaStack.pop();
      lastMetaElement = metaStack[metaStack.length - 1];
    }
    var element = lastMetaElement.element;
    var lastElementIndex = lastMetaElement.index;
    if (Array.isArray(element)) {
      element.push(obj);
    } else if (lastElementIndex === stack.length - 2) { // obj with key+value
      var key = stack.pop();
      element[key] = obj;
    } else {
      stack.push(obj); // obj with key only
    }
  }
}

exports.parse = function (str) {
  var stack = [];
  var metaStack = []; // stack for arrays and objects
  var i = 0;

  while (true) {
    var collationIndex = str[i++];
    //console.log('collationIndex is: ' + collationIndex);
    if (collationIndex === '}' ||
        collationIndex === ']' ||
        typeof collationIndex === 'undefined') {
      if (stack.length === 1) {
        return stack.pop();
      } else {
        pop(stack.pop(), stack, metaStack);
        continue;
      }
    }
    switch (collationIndex) {
      case ' ':
      case '\t':
      case '\n':
      case ':':
      case ',':
        break;
      case 'n':
        i += 3; // 'ull'
        pop(null, stack, metaStack);
        break;
      case 't':
        i += 3; // 'rue'
        pop(true, stack, metaStack);
        break;
      case 'f':
        i += 4; // 'alse'
        pop(false, stack, metaStack);
        break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '-':
        var parsedNum = '';
        i--;
        while (true) {
          var numChar = str[i++];
          if (/[\d\.\-e\+]/.test(numChar)) {
            parsedNum += numChar;
          } else {
            i--;
            break;
          }
        }
        pop(parseFloat(parsedNum), stack, metaStack);
        break;
      case '"':
        var parsedString = '';
        var lastCh;
        var numConsecutiveSlashes = 0;
        while (true) {
          var ch = str[i++];
          //console.log('ch is: ' + ch);
          //console.log('lastCh is: ' + lastCh);
          //console.log('numConsecutiveSlashes is: ' + numConsecutiveSlashes);
          if (ch !== '"' || (lastCh === '\\' &&
              numConsecutiveSlashes % 2 === 1)) {
            parsedString += ch;
            lastCh = ch;
            if (lastCh === '\\') {
              numConsecutiveSlashes++;
            } else {
              numConsecutiveSlashes = 0;
            }
          } else {
            break;
          }
        }
        //console.log('res is: ' + parsedString);
        pop(JSON.parse('"' + parsedString + '"'), stack, metaStack);
        break;
      case '[':
        var arrayElement = { element: [], index: stack.length };
        stack.push(arrayElement.element);
        metaStack.push(arrayElement);
        break;
      case '{':
        var objElement = { element: {}, index: stack.length };
        stack.push(objElement.element);
        metaStack.push(objElement);
        break;
      default:
        throw new Error(
          'unexpectedly reached end of input: ' + collationIndex);
    }
  }
};<commit_msg>remove console.log<commit_after>'use strict';

/**
 * Stringify/parse functions that don't operate
 * recursively, so they avoid call stack exceeded
 * errors.
 *
 * These don't implement the full JSON spec.
 * They just do enough to parse our rev tree objects,
 * which are pretty predictable.
 */
exports.stringify = function stringify(input) {
  var queue = [];
  queue.push({obj: input});

  var res = '';
  var next;
  while ((next = queue.pop())) {
    var obj = next.obj;
    var prefix = next.prefix || '';
    var val = next.val || '';
    res += prefix;
    if (val) {
      res += val;
    } else if (typeof obj !== 'object') {
      res += typeof obj === 'undefined' ? null : JSON.stringify(obj);
    } else if (obj === null) {
      res += 'null';
    } else if (Array.isArray(obj)) {
      queue.push({val: ']'});
      for (var i = obj.length - 1; i >= 0; i--) {
        var arrayPrefix = i === 0 ? '' : ',';
        queue.push({obj: obj[i], prefix: arrayPrefix});
      }
      queue.push({val: '['});
    } else { // object
      var keys = [];
      for (var k in obj) {
        if (obj.hasOwnProperty(k)) {
          keys.push(k);
        }
      }
      queue.push({val: '}'});
      for (var ii = keys.length - 1; ii >= 0; ii--) {
        var key = keys[ii];
        var value = obj[key];
        var objPrefix = (ii > 0 ? ',' : '');
        objPrefix += JSON.stringify(key) + ':';
        queue.push({obj: value, prefix: objPrefix});
      }
      queue.push({val: '{'});
    }
  }
  return res;
};

// Convenience function for the parse function.
// This pop function is basically copied from
// pouchCollate.parseIndexableString
function pop(obj, stack, metaStack) {
  if (metaStack.length) {
    var lastMetaElement = metaStack[metaStack.length - 1];
    if (obj === lastMetaElement.element) {
      // popping a meta-element, e.g. an object whose value is another object
      metaStack.pop();
      lastMetaElement = metaStack[metaStack.length - 1];
    }
    var element = lastMetaElement.element;
    var lastElementIndex = lastMetaElement.index;
    if (Array.isArray(element)) {
      element.push(obj);
    } else if (lastElementIndex === stack.length - 2) { // obj with key+value
      var key = stack.pop();
      element[key] = obj;
    } else {
      stack.push(obj); // obj with key only
    }
  }
}

exports.parse = function (str) {
  var stack = [];
  var metaStack = []; // stack for arrays and objects
  var i = 0;

  while (true) {
    var collationIndex = str[i++];
    if (collationIndex === '}' ||
        collationIndex === ']' ||
        typeof collationIndex === 'undefined') {
      if (stack.length === 1) {
        return stack.pop();
      } else {
        pop(stack.pop(), stack, metaStack);
        continue;
      }
    }
    switch (collationIndex) {
      case ' ':
      case '\t':
      case '\n':
      case ':':
      case ',':
        break;
      case 'n':
        i += 3; // 'ull'
        pop(null, stack, metaStack);
        break;
      case 't':
        i += 3; // 'rue'
        pop(true, stack, metaStack);
        break;
      case 'f':
        i += 4; // 'alse'
        pop(false, stack, metaStack);
        break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '-':
        var parsedNum = '';
        i--;
        while (true) {
          var numChar = str[i++];
          if (/[\d\.\-e\+]/.test(numChar)) {
            parsedNum += numChar;
          } else {
            i--;
            break;
          }
        }
        pop(parseFloat(parsedNum), stack, metaStack);
        break;
      case '"':
        var parsedString = '';
        var lastCh;
        var numConsecutiveSlashes = 0;
        while (true) {
          var ch = str[i++];
          if (ch !== '"' || (lastCh === '\\' &&
              numConsecutiveSlashes % 2 === 1)) {
            parsedString += ch;
            lastCh = ch;
            if (lastCh === '\\') {
              numConsecutiveSlashes++;
            } else {
              numConsecutiveSlashes = 0;
            }
          } else {
            break;
          }
        }
        pop(JSON.parse('"' + parsedString + '"'), stack, metaStack);
        break;
      case '[':
        var arrayElement = { element: [], index: stack.length };
        stack.push(arrayElement.element);
        metaStack.push(arrayElement);
        break;
      case '{':
        var objElement = { element: {}, index: stack.length };
        stack.push(objElement.element);
        metaStack.push(objElement);
        break;
      default:
        throw new Error(
          'unexpectedly reached end of input: ' + collationIndex);
    }
  }
};<|endoftext|>


<commit_before>/* global FileReader, FileError */
module.exports = FileSystem

function FileSystem (size) {
  if (!(this instanceof FileSystem)) {
    return new FileSystem()
  }

  window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem
  this.size = size
}

// Get a file as a data url from the filesystem based on name
FileSystem.prototype.get = function (file, callback) {
  requestFilesystem(this.size, function (fs) {
    fs.root.getFile(file, {}, function (fileEntry) {
      fileEntry.file(function (file) {
        var reader = new FileReader()

        reader.onloadend = function (e) {
          callback(this.result)
        }

        reader.readAsDataURL(file)
      }, errorHandler)
    }, errorHandler)
  })
}

// Add an array of files to the filesystem
FileSystem.prototype.add = function (files, callback) {
  requestFilesystem(this.size, function (file_system) {
    for (var i = 0; i !== files.length; i++) {
      addFile(file_system, files[i])
    }

    callback()
  })
}

// Add a single file to the file system
var addFile = function (file_system, file) {
  file_system.root.getFile(file.name, {create: true, exclusive: true}, function (entry) {
    entry.createWriter(function (writer) {
      writer.write(file)
    }, errorHandler)
  }, errorHandler)
}

// Get all files in the file system
FileSystem.prototype.list = function (callback) {
  requestFilesystem(this.size, function (file_system) {
    var directory_reader = file_system.root.createReader()
    var entries = []

    // Call the reader.readEntries() until no more results are returned.
    var readEntries = function () {
      directory_reader.readEntries(function (results) {
        if (!results.length) {
          callback(entries.sort())
        } else {
          entries = entries.concat(toArray(results))
          readEntries()
        }
      }, errorHandler)
    }

    // Start reading dirs.
    readEntries()
  })
}

// Delete a single file from the file system
FileSystem.prototype.delete = function (file, callback) {
  requestFilesystem(this.size, function (file_system) {
    file_system.root.getFile(file, {}, function (entry) {
      entry.remove(function () {
        callback()
      }, errorHandler)
    }, errorHandler)
  })
}

// Clear all files from the file system
FileSystem.prototype.clear = function (callback) {
  this.list(function (entries) {
    entries.forEach(function (entry) {
      entry.remove(function () {
      }, errorHandler)
    })
    callback()
  })
}

// Make sure that we always get back an array
function toArray (list) {
  return Array.prototype.slice.call(list || [], 0)
}

// Request a file system from the window object
function requestFilesystem (size, callback) {
  window.requestFileSystem(window.PERMANENT, size, callback, errorHandler)
}

// Handle any file errors
function errorHandler (e) {
  switch (e.code) {
    case FileError.QUOTA_EXCEEDED_ERR:
      console.error('QUOTA_EXCEEDED_ERR')
      break
    case FileError.NOT_FOUND_ERR:
      console.error('NOT_FOUND_ERR')
      break
    case FileError.SECURITY_ERR:
      console.error('SECURITY_ERR')
      break
    case FileError.INVALID_MODIFICATION_ERR:
      console.error('INVALID_MODIFICATION_ERR')
      break
    case FileError.INVALID_STATE_ERR:
      console.error('INVALID_STATE_ERR')
      break
    default:
      console.error('Unknown Error')
      break
  }
}
<commit_msg>Normalize variable names<commit_after>/* global FileReader, FileError */
module.exports = FileSystem

function FileSystem (size) {
  if (!(this instanceof FileSystem)) {
    return new FileSystem()
  }

  window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem
  this.size = size
}

// Get a file as a data url from the filesystem based on name
FileSystem.prototype.get = function (file, callback) {
  requestFilesystem(this.size, function (file_system) {
    file_system.root.getFile(file, {}, function (file_entry) {
      file_entry.file(function (file) {
        var reader = new FileReader()

        reader.onloadend = function (e) {
          callback(this.result)
        }

        reader.readAsDataURL(file)
      }, errorHandler)
    }, errorHandler)
  })
}

// Add an array of files to the filesystem
FileSystem.prototype.add = function (files, callback) {
  requestFilesystem(this.size, function (file_system) {
    for (var i = 0; i !== files.length; i++) {
      addFile(file_system, files[i])
    }

    callback()
  })
}

// Add a single file to the file system
var addFile = function (file_system, file) {
  file_system.root.getFile(file.name, {create: true, exclusive: true}, function (entry) {
    entry.createWriter(function (writer) {
      writer.write(file)
    }, errorHandler)
  }, errorHandler)
}

// Get all files in the file system
FileSystem.prototype.list = function (callback) {
  requestFilesystem(this.size, function (file_system) {
    var directory_reader = file_system.root.createReader()
    var entries = []

    // Call the reader.readEntries() until no more results are returned.
    var readEntries = function () {
      directory_reader.readEntries(function (results) {
        if (!results.length) {
          callback(entries.sort())
        } else {
          entries = entries.concat(toArray(results))
          readEntries()
        }
      }, errorHandler)
    }

    // Start reading dirs.
    readEntries()
  })
}

// Delete a single file from the file system
FileSystem.prototype.delete = function (file, callback) {
  requestFilesystem(this.size, function (file_system) {
    file_system.root.getFile(file, {}, function (entry) {
      entry.remove(function () {
        callback()
      }, errorHandler)
    }, errorHandler)
  })
}

// Clear all files from the file system
FileSystem.prototype.clear = function (callback) {
  this.list(function (entries) {
    entries.forEach(function (entry) {
      entry.remove(function () {
      }, errorHandler)
    })
    callback()
  })
}

// Make sure that we always get back an array
function toArray (list) {
  return Array.prototype.slice.call(list || [], 0)
}

// Request a file system from the window object
function requestFilesystem (size, callback) {
  window.requestFileSystem(window.PERMANENT, size, callback, errorHandler)
}

// Handle any file errors
function errorHandler (e) {
  switch (e.code) {
    case FileError.QUOTA_EXCEEDED_ERR:
      console.error('QUOTA_EXCEEDED_ERR')
      break
    case FileError.NOT_FOUND_ERR:
      console.error('NOT_FOUND_ERR')
      break
    case FileError.SECURITY_ERR:
      console.error('SECURITY_ERR')
      break
    case FileError.INVALID_MODIFICATION_ERR:
      console.error('INVALID_MODIFICATION_ERR')
      break
    case FileError.INVALID_STATE_ERR:
      console.error('INVALID_STATE_ERR')
      break
    default:
      console.error('Unknown Error')
      break
  }
}
<|endoftext|>


<commit_before>var Stream  = require('stream')
var path    = require('path')
var fs      = require('fs')
var mkdirp  = require('mkdirp')
var isodate = require('regexp-isodate')
//create a directory, and then start writing files into it.
//write each file upto max size,
//then create a new current file
//and then move the old files into an archive directory.
//with directories for year/month/day ?
//or make the depth of the directories configurable?

function pad (s) {
  return s < 10 ? '0'+s : ''+s
}

module.exports = function (dir, maxsize) {
  maxsize = maxsize || 1024*1024*1024
  var s = new Stream()
  s.buffer = []
  var _stream, start, moving, creating = false

  var n = 0

  function headfilename (start) {
    return path.join(dir, 'head' + start.toISOString() + '.log')
  }

  var headfile

  function datedir (date) {
    return path.join(
      dir,
      ''+ date.getFullYear(),
      pad(date.getMonth()),
      pad(date.getDay())
    )
  }

  function rotate (cb) {
d    if(!_stream) {
      create()
      if(cb) cb()
      return
    }
    //move the current file to it's archive location.
    //we will still be writing to this, but this is a rename
    //so the inode won't change so this should be okay.
    //I don't know how *your* filesystem works, though.

    written = 0
    moving = true
    fs.rename(
      headfile,
      path.join(datedir(start), start.toISOString() + '.log'),
      function (err) {
        moving = false
        //I don't know how to handle the error here.
        //probably we want to log it. emit for now
        //which will be easier to debug.
        if(err) return s.emit('error', err)
        create()
        if(cb) cb()
      })

  }

  function create () {
    //end old, and create a new file.
    if(creating) return
    creating = true
    if(_stream) {
      _stream.end()
      _stream = null
      fresh()
    }
    else
      check()

    function check () {
      fs.readdir(dir, function (err, ls) {
        var files = ls.filter(function (filename) {
          return isodate.test(filename)
        }).sort()
        var name = files.pop()
        if(!name) fresh()
        else {
          var filename = name ? path.join(dir, name) : null
          fs.stat(filename, function (err, stat) {
            if(err) {
              // if the file did not exist at this point,
              // it must have been deleted between when we got it from readdir
              // and now, so just ignore this and continue like it wasn't there.
              fresh()
            }
            else if(stat.size < maxsize) {
              var stream =
                fs.createWriteStream(headfile = filename, {flags: 'a'})
                start = stream.start = new Date(isodate.exec(name)[1])
              next(stream)
            }
            else fresh()
          })
        }
      })
    }

    function fresh () {
      start = new Date()
      var stream = fs.createWriteStream(headfile = headfilename(start))
      stream.start = start
      next(stream)
    }

    function next (stream) {

      var logdir = datedir(start)

      mkdirp(logdir, function (err) {
        if(err) return s.emit('error', err)

        _stream = stream
        creating = false

        while(s.buffer.length)
          _stream.write(s.buffer.shift())

        _stream.start = start

        _stream.on('drain', function () {
          s.emit('drain')
        })
        _stream.on('close', function () {
          s.emit('drain')
        })

      })
    }
  }

  var written = 0

  s.writable = true

  s.write = function (data, enc) {
    if((written += data.length) > maxsize) rotate()

    //while _stream does not exist, buffer and return paused.
    if(!_stream) {
      s.buffer.push(data)
      return false
    }
    return _stream.write(data, enc)
  }

  s.end = function (data, enc) {
    if(data)
      _stream.write(data, enc)
    rotate(function () {
      _stream.end()
    })
  }

  create()

  return s
}

<commit_msg>when reopening a file, remember it's size<commit_after>var Stream  = require('stream')
var path    = require('path')
var fs      = require('fs')
var mkdirp  = require('mkdirp')
var isodate = require('regexp-isodate')
//create a directory, and then start writing files into it.
//write each file upto max size,
//then create a new current file
//and then move the old files into an archive directory.
//with directories for year/month/day ?
//or make the depth of the directories configurable?

function pad (s) {
  return s < 10 ? '0'+s : ''+s
}

module.exports = function (dir, maxsize) {
  maxsize = maxsize || 1024*1024*1024
  var s = new Stream()
  s.buffer = []
  var _stream, start, moving, creating = false

  var n = 0

  function headfilename (start) {
    return path.join(dir, 'head' + start.toISOString() + '.log')
  }

  var headfile

  function datedir (date) {
    return path.join(
      dir,
      ''+ date.getFullYear(),
      pad(date.getMonth()),
      pad(date.getDay())
    )
  }

  function rotate (cb) {
    if(!_stream) {
      create()
      if(cb) cb()
      return
    }
    //move the current file to it's archive location.
    //we will still be writing to this, but this is a rename
    //so the inode won't change so this should be okay.
    //I don't know how *your* filesystem works, though.

    written = 0
    moving = true
    fs.rename(
      headfile,
      path.join(datedir(start), start.toISOString() + '.log'),
      function (err) {
        moving = false
        //I don't know how to handle the error here.
        //probably we want to log it. emit for now
        //which will be easier to debug.
        if(err) return s.emit('error', err)
        create()
        if(cb) cb()
      })

  }

  function create () {
    //end old, and create a new file.
    if(creating) return
    creating = true
    if(_stream) {
      _stream.end()
      _stream = null
      fresh()
    }
    else
      check()

    function check () {
      fs.readdir(dir, function (err, ls) {
        var files = ls.filter(function (filename) {
          return isodate.test(filename)
        }).sort()
        var name = files.pop()
        if(!name) fresh()
        else {
          var filename = name ? path.join(dir, name) : null
          fs.stat(filename, function (err, stat) {
            if(err) {
              // if the file did not exist at this point,
              // it must have been deleted between when we got it from readdir
              // and now, so just ignore this and continue like it wasn't there.
              return fresh()
            }
            else if(stat.size < maxsize) {
              written = stat.size
              var stream =
                fs.createWriteStream(headfile = filename, {flags: 'a'})
                start = stream.start = new Date(isodate.exec(name)[1])
              next(stream)
            }
            else fresh()
          })
        }
      })
    }

    function fresh () {
      start = new Date()
      var stream = fs.createWriteStream(headfile = headfilename(start))
      stream.start = start
      next(stream)
    }

    function next (stream) {

      var logdir = datedir(start)

      mkdirp(logdir, function (err) {
        if(err) return s.emit('error', err)

        _stream = stream
        creating = false

        while(s.buffer.length) {
          var data = s.buffer.shift()
          _stream.write(data)
          if((written += data.length) > maxsize) return rotate()
        }
        _stream.start = start

        _stream.on('drain', function () {
          s.emit('drain')
        })
        _stream.on('close', function () {
          s.emit('drain')
        })

      })
    }
  }

  var written = 0

  s.writable = true

  s.write = function (data, enc) {
    //while _stream does not exist, buffer and return paused.
    if(!_stream) {
      s.buffer.push(data)
      return false
    }
    if((written += data.length) > maxsize) rotate()
    return _stream.write(data, enc)
  }

  s.end = function (data, enc) {
    if(data)
      _stream.write(data, enc)
    rotate(function () {
      _stream.end()
    })
  }

  create()

  return s
}

<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-cli-nouislider',

  included: function(app) {
    this._super.included(app);
    if (!process.env.EMBER_CLI_FASTBOOT) {
      var bowerDirectory = app.bowerDirectory || 'bower_components';

      this.import({
        development: bowerDirectory + '/nouislider/distribute/nouislider.js',
        production: bowerDirectory + '/nouislider/distribute/nouislider.min.js'
      });
      this.import(bowerDirectory + '/nouislider/distribute/nouislider.min.css');

      this.import('vendor/nouislider/shim.js', {
        exports: { 'noUiSlider': ['default'] }
      });
    }
  }
};
<commit_msg>Fix asset import in ember-cli < 2.7<commit_after>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-cli-nouislider',

  included: function(app) {
    this._super.included(app);
    if (!process.env.EMBER_CLI_FASTBOOT) {
      // In nested addons, app.bowerDirectory might not be available
      var bowerDirectory = app.bowerDirectory || 'bower_components';
      // In ember-cli < 2.7, this.import is not available, so fall back to use app.import
      var importShim = typeof this.import !== 'undefined' ? this : app;

      importShim.import({
        development: bowerDirectory + '/nouislider/distribute/nouislider.js',
        production: bowerDirectory + '/nouislider/distribute/nouislider.min.js'
      });
      importShim.import(bowerDirectory + '/nouislider/distribute/nouislider.min.css');

      importShim.import('vendor/nouislider/shim.js', {
        exports: { 'noUiSlider': ['default'] }
      });
    }
  }
};
<|endoftext|>


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

var fs = require("fs");
var http = require("http");
var URL = require("url");
var heuristic = require("./heuristic");

module.exports = harmonica;
function harmonica(har, options) {
    var entries = har.log.entries;
    var config = options.config;
    var debug = options.debug;

    var server = http.createServer(function (request, response) {
        if (debug) {
            console.log(request.method, request.url);
        }
        request.parsedUrl = URL.parse(request.url, true);

        var entry = heuristic(entries, request);

        var where;
        for (var i = 0; i < config.mappings.length; i++) {
            if ((where = config.mappings[i](request.url))) {
                break;
            }
        }

        var content;
        if (where) {
            // If there's local content, but no entry in the HAR, create a shim
            // entry so that we can still serve the file
            // TODO: infer MIME type (maybe just use a static file serving package)
            if (!entry) {
                entry = {
                    response: {
                        status: 200,
                        headers: [],
                        content: {}
                    }
                };
            }
            // If we have a file location, then try and read it. If that fails, then
            // return a 404
            try {
                // TODO: do this asynchronously
                content = fs.readFileSync(where);
            } catch (e) {
                console.error("Error: Could not read", where, "requested from", request.url);
                entry = null;
            }
        }

        if (!entry) {
            console.log("Not found:", request.url);
            response.writeHead(404, "Not found", {"content-type": "text/plain"});
            response.end("404 Not found" + (where ? ", while looking for " + where : ""));
            return;
        }

        for (var h = 0; h < entry.response.headers.length; h++) {
            var name = entry.response.headers[h].name;
            var value = entry.response.headers[h].value;

            if (name.toLowerCase() === "content-length") continue;
            if (name.toLowerCase() === "content-encoding") continue;
            if (name.toLowerCase() === "cache-control") continue;
            if (name.toLowerCase() === "pragma") continue;

            var existing = response.getHeader(name);
            if (existing) {
                if (Array.isArray(existing)) {
                    response.setHeader(name, existing.concat(value));
                } else {
                    response.setHeader(name, [existing, value]);
                }
            } else {
                response.setHeader(name, value);
            }
        }

        // Try to make sure nothing is cached
        response.setHeader("cache-control", "no-cache, no-store, must-revalidate");
        response.setHeader("pragma", "no-cache");

        response.statusCode = entry.response.status;
        // We may already have content from a local file
        if (/^image\//.test(entry.response.content.mimeType)) {
            if (!content) {
                content = entry.response.content.text || "";
                content = new Buffer(content, 'base64');
            }
        } else {
            content = content || entry.response.content.text || "";
            content = content.toString();
            var context = {
                request: request,
                entry: entry
            };
            config.replacements.forEach(function (replacement) {
                content = replacement(content, context);
            });
        }

        if (entry.response.content.size > 0 && !content && !where) {
            console.error("Error:", entry.request.url, "has a non-zero size, but there is no content in the HAR file");
        }

        response.end(content);
    });

    server.listen(options.port);
}

function main() {
    var parseConfig = require("./parse-config");
    var argv = require("yargs")
        .usage("Usage: $0 [options] <.har file>")
        .options({
            c: {
                alias: "config",
                describe: "The config file to use"
            },
            p: {
                alias: "port",
                describe: "The port to run the proxy server on",
                default: 8080
            },
            d: {
                alias: "debug",
                describe: "Turn on debug logging",
                boolean: true
            }
        })
        .demand(1)
        .argv;

    var harPath = argv._[0];
    var har = JSON.parse(fs.readFileSync(harPath));

    var configPath = argv.config;
    if (!configPath && fs.existsSync(".harmonica.json")) {
        configPath = ".harmonica.json";
    }
    if (argv.debug) {
        if (configPath) {
            console.log("Using config file from", configPath);
        } else {
            console.log("No config file");
        }
    }
    var config = parseConfig(configPath ? fs.readFileSync(configPath, "utf8") : null);

    harmonica(har, {
        config: config,
        port: argv.port,
        debug: argv.debug
    });

    console.log("Listening at http://localhost:" + argv.port);
    console.log("Try " + har.log.entries[0].request.url.replace(/^https/, "http"));
}

if (require.main === module) {
    main();
}<commit_msg>Resolve mappings relative to the location of the config file<commit_after>#!/usr/bin/env node

var fs = require("fs");
var http = require("http");
var URL = require("url");
var PATH = require("path");
var heuristic = require("./heuristic");

module.exports = harmonica;
function harmonica(har, options) {
    var entries = har.log.entries;
    var config = options.config;
    var resolvePath = options.resolvePath;
    var debug = options.debug;

    var server = http.createServer(function (request, response) {
        if (debug) {
            console.log(request.method, request.url);
        }
        request.parsedUrl = URL.parse(request.url, true);

        var entry = heuristic(entries, request);

        var where;
        for (var i = 0; i < config.mappings.length; i++) {
            if ((where = config.mappings[i](request.url))) {
                where = PATH.resolve(resolvePath, where);
                break;
            }
        }

        var content;
        if (where) {
            // If there's local content, but no entry in the HAR, create a shim
            // entry so that we can still serve the file
            // TODO: infer MIME type (maybe just use a static file serving package)
            if (!entry) {
                entry = {
                    response: {
                        status: 200,
                        headers: [],
                        content: {}
                    }
                };
            }
            // If we have a file location, then try and read it. If that fails, then
            // return a 404
            try {
                // TODO: do this asynchronously
                content = fs.readFileSync(where);
            } catch (e) {
                console.error("Error: Could not read", where, "requested from", request.url);
                entry = null;
            }
        }

        if (!entry) {
            console.log("Not found:", request.url);
            response.writeHead(404, "Not found", {"content-type": "text/plain"});
            response.end("404 Not found" + (where ? ", while looking for " + where : ""));
            return;
        }

        for (var h = 0; h < entry.response.headers.length; h++) {
            var name = entry.response.headers[h].name;
            var value = entry.response.headers[h].value;

            if (name.toLowerCase() === "content-length") continue;
            if (name.toLowerCase() === "content-encoding") continue;
            if (name.toLowerCase() === "cache-control") continue;
            if (name.toLowerCase() === "pragma") continue;

            var existing = response.getHeader(name);
            if (existing) {
                if (Array.isArray(existing)) {
                    response.setHeader(name, existing.concat(value));
                } else {
                    response.setHeader(name, [existing, value]);
                }
            } else {
                response.setHeader(name, value);
            }
        }

        // Try to make sure nothing is cached
        response.setHeader("cache-control", "no-cache, no-store, must-revalidate");
        response.setHeader("pragma", "no-cache");

        response.statusCode = entry.response.status;
        // We may already have content from a local file
        if (/^image\//.test(entry.response.content.mimeType)) {
            if (!content) {
                content = entry.response.content.text || "";
                content = new Buffer(content, 'base64');
            }
        } else {
            content = content || entry.response.content.text || "";
            content = content.toString();
            var context = {
                request: request,
                entry: entry
            };
            config.replacements.forEach(function (replacement) {
                content = replacement(content, context);
            });
        }

        if (entry.response.content.size > 0 && !content && !where) {
            console.error("Error:", entry.request.url, "has a non-zero size, but there is no content in the HAR file");
        }

        response.end(content);
    });

    server.listen(options.port);
}

function main() {
    var parseConfig = require("./parse-config");
    var argv = require("yargs")
        .usage("Usage: $0 [options] <.har file>")
        .options({
            c: {
                alias: "config",
                describe: "The config file to use"
            },
            p: {
                alias: "port",
                describe: "The port to run the proxy server on",
                default: 8080
            },
            d: {
                alias: "debug",
                describe: "Turn on debug logging",
                boolean: true
            }
        })
        .demand(1)
        .argv;

    var harPath = argv._[0];
    var har = JSON.parse(fs.readFileSync(harPath));

    var configPath = argv.config;
    if (!configPath && fs.existsSync(".harmonica.json")) {
        configPath = ".harmonica.json";
    }
    if (argv.debug) {
        if (configPath) {
            console.log("Using config file from", configPath);
        } else {
            console.log("No config file");
        }
    }
    var config = parseConfig(configPath ? fs.readFileSync(configPath, "utf8") : null);

    harmonica(har, {
        config: config,
        resolvePath: PATH.dirname(configPath),
        port: argv.port,
        debug: argv.debug
    });

    console.log("Listening at http://localhost:" + argv.port);
    console.log("Try " + har.log.entries[0].request.url.replace(/^https/, "http"));
}

if (require.main === module) {
    main();
}<|endoftext|>


<commit_before>require('dotenv').config();
var body_parser = require('body-parser');
var express = require('express');
var flip = require('flip');
var qs = require('qs');
var request = require('request');

if (!process.env.APP_CLIENT_ID || !process.env.APP_CLIENT_SECRET || !process.env.PORT) {
  console.log('Error: Specify APP_CLIENT_ID, APP_CLIENT_SECRET, and PORT in environment');
  process.exit(1);
}

var app = express();
app.use(body_parser.json());
app.use(body_parser.urlencoded({ extended: true }));

// Handle oauth flow
app.get('/oauth', function(req, res) {
  var url = 'https://slack.com/api/oauth.access?' + qs.stringify({
    client_id: process.env.APP_CLIENT_ID,
    client_secret: process.env.APP_CLIENT_SECRET,
    code: req.query.code,
  });

  request.post(url, function(err, http, body) {
    if (err) {
      res.status(500).send('ERROR: ' + err);
    } else {
      res.send('Success!');
    }
  });
});

// Respond to webhooks
app.post('/webhook', function(req, res) {
  if (!req.body.token === process.env.APP_COMMAND_TOKEN) return res.sendStatus(403);
  if (!req.body.command || !req.body.command.startsWith('/tableflip')) return res.sendStatus(200);

  var flipped_text = flip(req.body.text) || '┻━┻';
  var response_text =  '(╯°□°）╯︵ ' + flipped_text;

  // Send our actual response async
  request({
    body: {
      response_type: 'in_channel',
      text: response_text,
    },
    json: true,
    method: 'post',
    uri: req.body.response_url,
  });

  // Let Slack know we didn't timeout
  res.send();
});

app.listen(process.env.PORT, function() {
  console.log('Server listening on', process.env.PORT);
});

app.get('health', function(req, res) {
  res.send('Ok');
});
<commit_msg>Tweak ping url<commit_after>require('dotenv').config();
var body_parser = require('body-parser');
var express = require('express');
var flip = require('flip');
var qs = require('qs');
var request = require('request');

if (!process.env.APP_CLIENT_ID || !process.env.APP_CLIENT_SECRET || !process.env.PORT) {
  console.log('Error: Specify APP_CLIENT_ID, APP_CLIENT_SECRET, and PORT in environment');
  process.exit(1);
}

var app = express();
app.use(body_parser.json());
app.use(body_parser.urlencoded({ extended: true }));

// Handle oauth flow
app.get('/oauth', function(req, res) {
  var url = 'https://slack.com/api/oauth.access?' + qs.stringify({
    client_id: process.env.APP_CLIENT_ID,
    client_secret: process.env.APP_CLIENT_SECRET,
    code: req.query.code,
  });

  request.post(url, function(err, http, body) {
    if (err) {
      res.status(500).send('ERROR: ' + err);
    } else {
      res.send('Success!');
    }
  });
});

// Respond to webhooks
app.post('/webhook', function(req, res) {
  if (!req.body.token === process.env.APP_COMMAND_TOKEN) return res.sendStatus(403);
  if (!req.body.command || !req.body.command.startsWith('/tableflip')) return res.sendStatus(200);

  var flipped_text = flip(req.body.text) || '┻━┻';
  var response_text =  '(╯°□°）╯︵ ' + flipped_text;

  // Send our actual response async
  request({
    body: {
      response_type: 'in_channel',
      text: response_text,
    },
    json: true,
    method: 'post',
    uri: req.body.response_url,
  });

  // Let Slack know we didn't timeout
  res.send();
});

app.get('/ping', function(req, res) {
  res.sendStatus(200);
});

app.listen(process.env.PORT, function() {
  console.log('Server listening on', process.env.PORT);
});
<|endoftext|>


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

const resolve = require('path').resolve;
const dirname = require('path').dirname;
const readFile = require('fs').readFile;
const Flow = require(__dirname + '/node_modules/flow');
const Adapter = require(__dirname + '/lib/adapters/cayley');
const entrypoint_name = process.argv[2];
const app_config = resolve(process.argv[3] || './flow.json');
const base_path = dirname(app_config);

!entrypoint_name && error('Missing entrypoint argument.');
initEntrypoint(getEntrypoint(require(app_config)));

function initEntrypoint (entrypoint) {
    let flow = Flow(Adapter(entrypoint))(entrypoint.emit);
    flow.on('data', chunk => process.stdout.write(chunk.toString()));
    flow.on('error', error => process.stderr.write(error.stack.toString() + '\n'));
    flow.end(1);
}

function getEntrypoint (config) {

    if (!config.entrypoints && !config.entrypoints.length) {
        error('No entrypoints defined in config.');
    }

    let entrypoint = config.entrypoints.find((item) => {
        return item.name === entrypoint_name;
    });

    if (!entrypoint.emit) {
        error('No event defined in entrypoint.');
    }

    entrypoint.base = base_path;

    if (entrypoint.env && entrypoint.env.length) {
        environment(entrypoint, config);
    }

    return entrypoint;
}

function environment (entrypoint, config) {
    process.flow_env = {};
    entrypoint.env.forEach((env) => {

        env = config.environments.find((environment) => {
            return environment.name === env;
        });

        !env && error('Entrypoint environment reference "' + name + '" does not exist.');

        Object.assign(process.flow_env, env.vars);
    });

    delete entrypoint.env;
}

function error (msg) {
    throw new Error('Flow-nodejs: ' + msg);
}
<commit_msg>pass entrypoint session to first event<commit_after>#!/usr/bin/env node

const resolve = require('path').resolve;
const dirname = require('path').dirname;
const readFile = require('fs').readFile;
const Flow = require(__dirname + '/node_modules/flow');
const Adapter = require(__dirname + '/lib/adapters/cayley');
const entrypoint_name = process.argv[2];
const app_config = resolve(process.argv[3] || './flow.json');
const base_path = dirname(app_config);

!entrypoint_name && error('Missing entrypoint argument.');
initEntrypoint(getEntrypoint(require(app_config)));

function initEntrypoint (entrypoint) {
    let flow = Flow(Adapter(entrypoint))(entrypoint.emit, {session: {role: entrypoint.role}});
    flow.on('data', chunk => process.stdout.write(chunk.toString()));
    flow.on('error', error => process.stderr.write(error.stack.toString() + '\n'));
    flow.end(1);
}

function getEntrypoint (config) {

    if (!config.entrypoints && !config.entrypoints.length) {
        error('No entrypoints defined in config.');
    }

    let entrypoint = config.entrypoints.find((item) => {
        return item.name === entrypoint_name;
    });

    if (!entrypoint.emit) {
        error('No event defined in entrypoint.');
    }

    entrypoint.base = base_path;
    entrypoint.role = entrypoint.role || '*';//'__entrypoint__';

    if (entrypoint.env && entrypoint.env.length) {
        environment(entrypoint, config);
    }

    return entrypoint;
}

function environment (entrypoint, config) {
    process.flow_env = {};
    entrypoint.env.forEach((env) => {

        env = config.environments.find((environment) => {
            return environment.name === env;
        });

        !env && error('Entrypoint environment reference "' + name + '" does not exist.');

        Object.assign(process.flow_env, env.vars);
    });

    delete entrypoint.env;
}

function error (msg) {
    throw new Error('Flow-nodejs: ' + msg);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Teppo Kurki <teppo.kurki@iki.fi>
 *
 * 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.
 */

const debug = require('debug')('marinetrafficreporter')

const Bacon = require('baconjs');

const AisEncode = require("ggencoder").AisEncode
const dgram = require('dgram')

module.exports = function(app) {
  var udpSocket
  var plugin = {}
  var unsubscribe = undefined

  plugin.start = function(props) {
    debug("starting with " + props.ipaddress + ":" + props.port)
    var mmsi = app.config.settings.vessel.mmsi

    try {
      udpSocket = require('dgram').createSocket('udp4')
      unsubscribe = Bacon.combineWith(function(position, sog, cog) {
        return createPositionReportMessage(mmsi, position.latitude, position.longitude, mpsToKn(sog), cog)
      }, ['navigation.position', 'navigation.speedOverGround', 'navigation.courseOverGroundTrue'].map(app.streambundle.getSelfStream, app.streambundle)).changes().debounceImmediate(60000).onValue(msg => {
        sendPositionReportMsg(msg, props.ipaddress, props.port)
      })
    } catch (e) {
      plugin.started = false
      console.log(e)
    }
    debug("started")
  };

  plugin.stop = function() {
    debug("stopping")
    if (unsubscribe) {
      unsubscribe()
    }
    debug("stopped")
  };

  plugin.id = "marinetrafficreporter"
  plugin.name = "Marine Traffic Reporter"
  plugin.description = "Plugin that reports self's position periodically to Marine Traffic via UDP ASI messages"

  plugin.schema = {
    type: "object",
    required: [
      "ipaddress", "port"
    ],
    properties: {
      ipaddress: {
        type: "string",
        title: "UDP endpoint IP address",
        default: "0.0.0.0"
      },
      port: {
        type: "number",
        title: "Port",
        default: "12345"
      }
    }
  }

  return plugin;

  function sendPositionReportMsg(msg, ip, port) {
    debug(ip + ':' + port + ' ' + JSON.stringify(msg.nmea))
    if (udpSocket) {
      udpSocket.send(msg.nmea, 0, msg.nmea.length, port, ip, err => {
        if (err) {
          console.log('Failed to send position report.', err)
        }
      })
    }
  }
}

function createPositionReportMessage(mmsi, lat, lon, sog, cog) {
  return new AisEncode({
    aistype: 18, // class B position report
    repeat: 0,
    mmsi: mmsi,
    sog: sog,
    accuracy: 0, // 0 = regular GPS, 1 = DGPS
    lon: lon,
    lat: lat,
    cog: cog
  })
}

function radsToDeg(radians) {
  return radians * 180 / Math.PI
}

function mpsToKn(mps) {
  return 1.9438444924574 * mps
}
<commit_msg>Fix COG to be in degrees and add heading true to posision report<commit_after>/*
 * Copyright 2016 Teppo Kurki <teppo.kurki@iki.fi>
 *
 * 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.
 */

const debug = require('debug')('marinetrafficreporter')

const Bacon = require('baconjs');

const AisEncode = require("ggencoder").AisEncode
const dgram = require('dgram')

module.exports = function(app) {
  var udpSocket
  var plugin = {}
  var unsubscribe = undefined

  plugin.start = function(props) {
    debug("starting with " + props.ipaddress + ":" + props.port)
    var mmsi = app.config.settings.vessel.mmsi

    try {
      udpSocket = require('dgram').createSocket('udp4')
      unsubscribe = Bacon.combineWith(function(position, sog, cog, head) {
        return createPositionReportMessage(mmsi, position.latitude, position.longitude, mpsToKn(sog), cog, head)
      }, ['navigation.position', 'navigation.speedOverGround', 'navigation.courseOverGroundTrue', 'navigation.headingTrue'].map(app.streambundle.getSelfStream, app.streambundle)).changes().debounceImmediate(60000).onValue(msg => {
        sendPositionReportMsg(msg, props.ipaddress, props.port)
      })
    } catch (e) {
      plugin.started = false
      console.log(e)
    }
    debug("started")
  };

  plugin.stop = function() {
    debug("stopping")
    if (unsubscribe) {
      unsubscribe()
    }
    debug("stopped")
  };

  plugin.id = "marinetrafficreporter"
  plugin.name = "Marine Traffic Reporter"
  plugin.description = "Plugin that reports self's position periodically to Marine Traffic via UDP ASI messages"

  plugin.schema = {
    type: "object",
    required: [
      "ipaddress", "port"
    ],
    properties: {
      ipaddress: {
        type: "string",
        title: "UDP endpoint IP address",
        default: "0.0.0.0"
      },
      port: {
        type: "number",
        title: "Port",
        default: "12345"
      }
    }
  }

  return plugin;

  function sendPositionReportMsg(msg, ip, port) {
    debug(ip + ':' + port + ' ' + JSON.stringify(msg.nmea))
    if (udpSocket) {
      udpSocket.send(msg.nmea, 0, msg.nmea.length, port, ip, err => {
        if (err) {
          console.log('Failed to send position report.', err)
        }
      })
    }
  }
}

function createPositionReportMessage(mmsi, lat, lon, sog, cog, head) {
  return new AisEncode({
    aistype: 18, // class B position report
    repeat: 0,
    mmsi: mmsi,
    sog: sog,
    accuracy: 0, // 0 = regular GPS, 1 = DGPS
    lon: lon,
    lat: lat,
    cog: radsToDeg(cog),
    hdg: radsToDeg(head)
  })
}

function radsToDeg(radians) {
  return radians * 180 / Math.PI
}

function mpsToKn(mps) {
  return 1.9438444924574 * mps
}
<|endoftext|>


<commit_before><commit_msg>Require dependument<commit_after>var dependument = require('dependument');
<|endoftext|>


<commit_before>ark = {
	crypto : require("./lib/transactions/crypto.js"),
	delegate : require("./lib/transactions/delegate.js"),
	signature : require("./lib/transactions/signature.js"),
	transaction : require("./lib/transactions/transaction.js"),
	vote : require("./lib/transactions/vote.js"),
	ipfs : require("./lib/transactions/ipfs.js"),
	wallet : {
		hdnode : require("./lib/hdnode.js")
	},
	ecpair : require("./lib/ecpair.js"),
	ecsignature : require("./lib/ecsignature.js"),
	networks : require("./lib/networks.js")

}

module.exports = ark;
<commit_msg>improve compatibility with bitcoinjs-lib<commit_after>ark = {
	crypto : require("./lib/transactions/crypto.js"),
	delegate : require("./lib/transactions/delegate.js"),
	signature : require("./lib/transactions/signature.js"),
	transaction : require("./lib/transactions/transaction.js"),
	vote : require("./lib/transactions/vote.js"),
	ipfs : require("./lib/transactions/ipfs.js"),
	networks : require("./lib/networks.js"),

	ECPair : require("./lib/ecpair.js"),
	HDNode : require("./lib/hdnode.js"),
	ECSignature : require("./lib/ecsignature.js"),
}

// extra aliases for bitcoinlib-js compatibility
var libCrypto = require('./lib/crypto.js')
for (var method in libCrypto) {
	ark.crypto[method] = libCrypto[method]
}

module.exports = ark;
<|endoftext|>


<commit_before>const dgram = require("dgram");
const ip = require("ip");

const PORT = 1337;
//TODO improve argument parsing
const INTERFACES = (process.argv.slice(2).length > 0) ? process.argv.slice(2) : ["wlp3s0"];
const ALL_NODES_ADDRESS = "ff02::1" // this has link scope not node scope

// map of sockets for each interface
// TODO maybe make a difference between listening and sending sockets
let servers = new Map();

// key aka destination is combinationn of address (ip) and port
// TODO does the port help in anyway?
let routingTable = new Map();

const createServer = function createServer(interface, includeInRoutingTable) {

  let server = dgram.createSocket("udp6");

  server.on("listening", function(){
    let address = server.address()
    console.info(`Listening on ${address.address}:${address.port}`);
    if(includeInRoutingTable) {
      //routingTable.set(`${address.address}:${address.port}`, { 'cost': 0 });
      let destination = {
        'cost': 0,
        'link': interface,
        'time': null
      };
      routingTable.set(address.address, destination);
    }
  });
  server.on("message", function(message, remote){
    //do not handle messages from us
    //TODO remove map?
    let localAddresses = INTERFACES.map(function(interface){
      return ip.address(interface, "ipv6");
    });
    //TODO maybe check port too?
    if(localAddresses.includes(remote.address)) {
      return;
    }
    console.info(`Message arrived from ${remote.address}:${remote.port}`);
    console.info(message.toString());
  });
  server.on("error", function(error) {
    console.error(error);
  })

  return server;
};

const sendVector = function sendVector(vector, interface){
  console.info(`Broadcasting over ${interface.address().address}:`);
  console.info(vector);
  interface.send(JSON.stringify(vector), PORT, ALL_NODES_ADDRESS); //TODO maybe add a call back
};

const sendVectors = function sendVectors(){

  let vector = [];

  routingTable.forEach(function(destination, destinationAddress){
    vector.push([destinationAddress, destination.cost]);
  });

  INTERFACES.forEach(function(interface){
    sendVector(vector, servers.get(interface));
  });
};

setInterval(sendVectors, 1000);

// listen on multiple interfaces
INTERFACES.forEach(function(interface){
  //TODO there can be multiple addresses, which one should we use?
  let address = ip.address(interface, "ipv6");
  //TODO this is wrong!?!! address = ALL_NODES_ADDRESS;
  let server = createServer();
  console.info(`Binding server to ${address} on ${interface}`);
  //TODO check if we need the interface here
  server.bind(PORT, `${address}%${interface}`);
  servers.set(interface, server);

  //TODO THINK!!!
  //bind to ALL_NODES_ADDRESS of interface
  server = createServer();
  server.bind(PORT, `${ALL_NODES_ADDRESS}%${interface}`);
});
<commit_msg>use JSON.parse to parse the received message and get a vector/map<commit_after>const dgram = require("dgram");
const ip = require("ip");

const PORT = 1337;
//TODO improve argument parsing
const INTERFACES = (process.argv.slice(2).length > 0) ? process.argv.slice(2) : ["wlp3s0"];
const ALL_NODES_ADDRESS = "ff02::1" // this has link scope not node scope

// map of sockets for each interface
// TODO maybe make a difference between listening and sending sockets
let servers = new Map();

// key aka destination is combinationn of address (ip) and port
// TODO does the port help in anyway?
let routingTable = new Map();

const createServer = function createServer(interface, includeInRoutingTable) {

  let server = dgram.createSocket("udp6");

  server.on("listening", function(){
    let address = server.address()
    console.info(`Listening on ${address.address}:${address.port}`);
    if(includeInRoutingTable) {
      //routingTable.set(`${address.address}:${address.port}`, { 'cost': 0 });
      let destination = {
        'cost': 0,
        'link': interface,
        'time': null
      };
      routingTable.set(address.address, destination);
    }
  });
  server.on("message", function(message, remote){
    //do not handle messages from us
    //TODO remove map?
    let localAddresses = INTERFACES.map(function(interface){
      return ip.address(interface, "ipv6");
    });
    //TODO maybe check port too?
    if(localAddresses.includes(remote.address)) {
      return;
    }
    let vector = new Map(JSON.parse(message));
    console.info(`Message arrived from ${remote.address}:${remote.port}`);
    console.info(message.toString());
  });
  server.on("error", function(error) {
    console.error(error);
  })

  return server;
};

const sendVector = function sendVector(vector, interface){
  console.info(`Broadcasting over ${interface.address().address}:`);
  console.info(vector);
  interface.send(JSON.stringify(vector), PORT, ALL_NODES_ADDRESS); //TODO maybe add a call back
};

const sendVectors = function sendVectors(){

  let vector = [];

  routingTable.forEach(function(destination, destinationAddress){
    vector.push([destinationAddress, destination.cost]);
  });

  INTERFACES.forEach(function(interface){
    sendVector(vector, servers.get(interface));
  });
};

setInterval(sendVectors, 1000);

// listen on multiple interfaces
INTERFACES.forEach(function(interface){
  //TODO there can be multiple addresses, which one should we use?
  let address = ip.address(interface, "ipv6");
  //TODO this is wrong!?!! address = ALL_NODES_ADDRESS;
  let server = createServer();
  console.info(`Binding server to ${address} on ${interface}`);
  //TODO check if we need the interface here
  server.bind(PORT, `${address}%${interface}`);
  servers.set(interface, server);

  //TODO THINK!!!
  //bind to ALL_NODES_ADDRESS of interface
  server = createServer();
  server.bind(PORT, `${ALL_NODES_ADDRESS}%${interface}`);
});
<|endoftext|>


<commit_before>require("./dist/angular-stats");
module.exports = "angular-stats";<commit_msg>deletion of index.js<commit_after><|endoftext|>