<commit_before>///<reference path="../typings/jquery/jquery.d.ts"/>
var Anterec;
(function (Anterec) {
    var JsDragTable = (function () {
        function JsDragTable(target) {
            this.offsetX = 5;
            this.offsetY = 5;
            this.container = target;
            this.rebind();
        }
        JsDragTable.prototype.rebind = function () {
            var _this = this;
            $(this.container).find("th").each(function (headerIndex, header) {
                $(header).off("mousedown touchstart");
                $(header).off("mouseup touchend");
                $(header).on("mousedown touchstart", function (event) {
                    _this.selectColumn($(header), event);
                });
                $(header).on("mouseup touchend", function (event) {
                    _this.dropColumn($(header), event);
                });
            });
            $(this.container).on("mouseup touchend", function () {
                _this.cancelColumn();
            });
        };

        JsDragTable.prototype.selectColumn = function (header, event) {
            var _this = this;
            event.preventDefault();
            var userEvent = new UserEvent(event);
            this.selectedHeader = header;
            var sourceIndex = this.selectedHeader.index() + 1;
            var cells = [];

            $(this.container).find("tr td:nth-child(" + sourceIndex + ")").each(function (cellIndex, cell) {
                cells[cells.length] = cell;
            });

            this.draggableContainer = $("<div/>");
            this.draggableContainer.addClass("jsdragtable-contents");
            this.draggableContainer.css({ position: "absolute", left: userEvent.event.pageX + this.offsetX, top: userEvent.event.pageY + this.offsetY });

            var dragtable = this.createDraggableTable(header);

            $(cells).each(function (cellIndex, cell) {
                var tr = $("<tr/>");
                var td = $("<td/>");
                $(td).html($(cells[cellIndex]).html());
                $(tr).append(td);
                $(dragtable).find("tbody").append(tr);
            });

            this.draggableContainer.append(dragtable);
            $("body").append(this.draggableContainer);
            $(this.container).on("mousemove touchmove", function (event) {
                _this.moveColumn($(header), event);
            });
            $(".jsdragtable-contents").on("mouseup touchend", function () {
                _this.cancelColumn();
            });
        };

        JsDragTable.prototype.moveColumn = function (header, event) {
            event.preventDefault();
            if (this.selectedHeader !== null) {
                var userEvent = new UserEvent(event);
                this.draggableContainer.css({ left: userEvent.event.pageX + this.offsetX, top: userEvent.event.pageY + this.offsetY });
            }
        };

        JsDragTable.prototype.dropColumn = function (header, event) {
            var _this = this;
            event.preventDefault();
            var sourceIndex = this.selectedHeader.index() + 1;
            var targetIndex = $(event.target).index() + 1;
            var tableColumns = $(this.container).find("th").length;

            var userEvent = new UserEvent(event);
            if (userEvent.isTouchEvent) {
                header = $(document.elementFromPoint(userEvent.event.clientX, userEvent.event.clientY));
                targetIndex = $(header).prevAll().length + 1;
            }

            if (sourceIndex !== targetIndex) {
                var cells = [];
                $(this.container).find("tr td:nth-child(" + sourceIndex + ")").each(function (cellIndex, cell) {
                    cells[cells.length] = cell;
                    $(cell).remove();
                    $(_this.selectedHeader).remove();
                });

                if (targetIndex >= tableColumns) {
                    targetIndex = tableColumns - 1;
                    this.insertCells(cells, targetIndex, function (cell, element) {
                        $(cell).after(element);
                    });
                } else {
                    this.insertCells(cells, targetIndex, function (cell, element) {
                        $(cell).before(element);
                    });
                }

                $(this.container).off("mousemove touchmove");
                $(".jsdragtable-contents").remove();
                this.draggableContainer = null;
                this.selectedHeader = null;
                this.rebind();
            }
        };

        JsDragTable.prototype.cancelColumn = function () {
            $(this.container).off("mousemove touchmove");
            $(".jsdragtable-contents").remove();
            this.draggableContainer = null;
            this.selectedHeader = null;
            this.rebind();
        };

        JsDragTable.prototype.createDraggableTable = function (header) {
            var table = $("<table/>");
            var thead = $("<thead/>");
            var tbody = $("<tbody/>");
            var tr = $("<tr/>");
            var th = $("<th/>");
            $(table).addClass($(this.container).attr("class"));
            $(table).width($(header).width());
            $(th).html($(header).html());
            $(tr).append(th);
            $(thead).append(tr);
            $(table).append(thead);
            $(table).append(tbody);
            return table;
        };

        JsDragTable.prototype.insertCells = function (cells, columnIndex, callback) {
            var _this = this;
            $(this.container).find("tr td:nth-child(" + columnIndex + ")").each(function (cellIndex, cell) {
                callback(cell, $(cells[cellIndex]));
            });
            $(this.container).find("th:nth-child(" + columnIndex + ")").each(function (cellIndex, cell) {
                callback(cell, $(_this.selectedHeader));
            });
        };
        return JsDragTable;
    })();
    Anterec.JsDragTable = JsDragTable;

    var UserEvent = (function () {
        function UserEvent(event) {
            this.event = event;
            if (event.originalEvent && event.originalEvent.touches && event.originalEvent.changedTouches) {
                this.event = event.originalEvent.touches[0] || event.originalEvent.changedTouches[0];
                this.isTouchEvent = true;
            }
        }
        return UserEvent;
    })();
})(Anterec || (Anterec = {}));
jQuery.fn.extend({
    jsdragtable: function () {
        return new Anterec.JsDragTable(this);
    }
});
<commit_msg>Update jsdragtable.js<commit_after>///<reference path="../typings/jquery/jquery.d.ts"/>
var Anterec;
(function (Anterec) {
    var JsDragTable = (function () {
        function JsDragTable(target) {
            this.offsetX = 5;
            this.offsetY = 5;
            this.container = target;
            this.rebind();
        }
        JsDragTable.prototype.rebind = function () {
            var _this = this;
            $(this.container).find("th").each(function (headerIndex, header) {
                $(header).off("mousedown touchstart");
                $(header).off("mouseup touchend");
                $(header).on("mousedown touchstart", function (event) {
                    _this.selectColumn($(header), event);
                });
                $(header).on("mouseup touchend", function (event) {
                    _this.dropColumn($(header), event);
                });
            });
            $(this.container).on("mouseup touchend", function () {
                _this.cancelColumn();
            });
        };

        JsDragTable.prototype.selectColumn = function (header, event) {
            var _this = this;
            event.preventDefault();
            var userEvent = new UserEvent(event);
            this.selectedHeader = header;
            var sourceIndex = this.selectedHeader.index() + 1;
            var cells = [];

            $(this.container).find("tr td:nth-child(" + sourceIndex + ")").each(function (cellIndex, cell) {
                cells[cells.length] = cell;
            });

            this.draggableContainer = $("<div/>");
            this.draggableContainer.addClass("jsdragtable-contents");
            this.draggableContainer.css({ position: "absolute", left: userEvent.event.pageX + this.offsetX, top: userEvent.event.pageY + this.offsetY });

            var dragtable = this.createDraggableTable(header);

            $(cells).each(function (cellIndex, cell) {
                var tr = $("<tr/>");
                var td = $("<td/>");
                $(td).html($(cells[cellIndex]).html());
                $(tr).append(td);
                $(dragtable).find("tbody").append(tr);
            });

            this.draggableContainer.append(dragtable);
            $("body").append(this.draggableContainer);
            $(this.container).on("mousemove touchmove", function (event) {
                _this.moveColumn($(header), event);
            });
            $(".jsdragtable-contents").on("mouseup touchend", function () {
                _this.cancelColumn();
            });
        };

        JsDragTable.prototype.moveColumn = function (header, event) {
            event.preventDefault();
            if (this.selectedHeader !== null) {
                var userEvent = new UserEvent(event);
                this.draggableContainer.css({ left: userEvent.event.pageX + this.offsetX, top: userEvent.event.pageY + this.offsetY });
            }
        };

        JsDragTable.prototype.dropColumn = function (header, event) {
            var _this = this;
            event.preventDefault();
            var sourceIndex = this.selectedHeader.index() + 1;
            var targetIndex = $(event.target).index() + 1;
            var tableColumns = $(this.container).find("th").length;

            var userEvent = new UserEvent(event);
            if (userEvent.isTouchEvent) {
                header = $(document.elementFromPoint(userEvent.event.clientX, userEvent.event.clientY));
                targetIndex = $(header).prevAll().length + 1;
            }

            if (sourceIndex !== targetIndex) {
                var cells = [];
                $(this.container).find("tr td:nth-child(" + sourceIndex + ")").each(function (cellIndex, cell) {
                    cells[cells.length] = cell;
                    $(cell).remove();
                    $(_this.selectedHeader).remove();
                });

                if (targetIndex >= tableColumns) {
                    targetIndex = tableColumns - 1;
                    this.insertCells(cells, targetIndex, function (cell, element) {
                        $(cell).after(element);
                    });
                } else {
                    this.insertCells(cells, targetIndex, function (cell, element) {
                        $(cell).before(element);
                    });
                }

                $(this.container).off("mousemove touchmove");
                $(".jsdragtable-contents").remove();
                this.draggableContainer = null;
                this.selectedHeader = null;
                this.rebind();
            }
        };

        JsDragTable.prototype.cancelColumn = function () {
            $(this.container).off("mousemove touchmove");
            $(".jsdragtable-contents").remove();
            this.draggableContainer = null;
            this.selectedHeader = null;
        };

        JsDragTable.prototype.createDraggableTable = function (header) {
            var table = $("<table/>");
            var thead = $("<thead/>");
            var tbody = $("<tbody/>");
            var tr = $("<tr/>");
            var th = $("<th/>");
            $(table).addClass($(this.container).attr("class"));
            $(table).width($(header).width());
            $(th).html($(header).html());
            $(tr).append(th);
            $(thead).append(tr);
            $(table).append(thead);
            $(table).append(tbody);
            return table;
        };

        JsDragTable.prototype.insertCells = function (cells, columnIndex, callback) {
            var _this = this;
            $(this.container).find("tr td:nth-child(" + columnIndex + ")").each(function (cellIndex, cell) {
                callback(cell, $(cells[cellIndex]));
            });
            $(this.container).find("th:nth-child(" + columnIndex + ")").each(function (cellIndex, cell) {
                callback(cell, $(_this.selectedHeader));
            });
        };
        return JsDragTable;
    })();
    Anterec.JsDragTable = JsDragTable;

    var UserEvent = (function () {
        function UserEvent(event) {
            this.event = event;
            if (event.originalEvent && event.originalEvent.touches && event.originalEvent.changedTouches) {
                this.event = event.originalEvent.touches[0] || event.originalEvent.changedTouches[0];
                this.isTouchEvent = true;
            }
        }
        return UserEvent;
    })();
})(Anterec || (Anterec = {}));
jQuery.fn.extend({
    jsdragtable: function () {
        return new Anterec.JsDragTable(this);
    }
});
<|endoftext|>


<commit_before>
module.exports = LinkWriter

var fs = require("graceful-fs")
  , Writer = require("./writer.js")
  , inherits = require("inherits")
  , collect = require("./collect.js")
  , path = require("path")
  , rimraf = require("rimraf")

inherits(LinkWriter, Writer)

function LinkWriter (props) {
  var me = this
  if (!(me instanceof LinkWriter)) throw new Error(
    "LinkWriter must be called as constructor.")

  // should already be established as a Link type
  if (!((props.type === "Link" && props.Link) ||
        (props.type === "SymbolicLink" && props.SymbolicLink))) {
    throw new Error("Non-link type "+ props.type)
  }

  if (!props.linkpath) {
    me.error("Need linkpath property to create " + props.type)
  }

  Writer.call(this, props)
}

LinkWriter.prototype._create = function () {
  // console.error(" LW _create")
  var me = this
    , hard = me.type === "Link" || process.platform === "win32"
    , link = hard ? "link" : "symlink"
    , lp = hard ? path.resolve(me.dirname, me.linkpath) : me.linkpath

  // can only change the link path by clobbering
  // For hard links, let's just assume that's always the case, since
  // there's no good way to read them if we don't already know.
  if (hard) return clobber(me, lp, link)

  fs.readlink(me._path, function (er, p) {
    // only skip creation if it's exactly the same link
    if (p && p === lp) return finish(me)
    clobber(me, lp, link)
  })
}

function clobber (me, lp, link) {
  rimraf(me._path, function (er) {
    if (er) return me.error(er)
    create(me, lp, link)
  })
}

function create (me, lp, link) {
  fs[link](lp, me._path, function (er) {
    // if this is a hard link, and we're in the process of writing out a
    // directory, it's very possible that the thing we're linking to
    // doesn't exist yet (especially if it was intended as a symlink),
    // so swallow ENOENT errors here and just soldier in.
    if (er) {
      if (er.code === "ENOENT" && process.platform === "win32") {
        me.ready = true
        me.emit("ready")
        me.emit("end")
        me.emit("close")
        me.end = me._finish = function () {}
      } else return me.error(er)
    }
    finish(me)
  })
}

function finish (me) {
  me.ready = true
  me.emit("ready")
  if (me._ended && !me._finished) me._finish()
}

LinkWriter.prototype.end = function () {
  // console.error("LW finish in end")
  this._ended = true
  if (this.ready) {
    this._finished = true
    this._finish()
  }
}
<commit_msg>Fix isaacs/npm#1883 Symlinks can fail in many ways on windows.<commit_after>
module.exports = LinkWriter

var fs = require("graceful-fs")
  , Writer = require("./writer.js")
  , inherits = require("inherits")
  , collect = require("./collect.js")
  , path = require("path")
  , rimraf = require("rimraf")

inherits(LinkWriter, Writer)

function LinkWriter (props) {
  var me = this
  if (!(me instanceof LinkWriter)) throw new Error(
    "LinkWriter must be called as constructor.")

  // should already be established as a Link type
  if (!((props.type === "Link" && props.Link) ||
        (props.type === "SymbolicLink" && props.SymbolicLink))) {
    throw new Error("Non-link type "+ props.type)
  }

  if (!props.linkpath) {
    me.error("Need linkpath property to create " + props.type)
  }

  Writer.call(this, props)
}

LinkWriter.prototype._create = function () {
  // console.error(" LW _create")
  var me = this
    , hard = me.type === "Link" || process.platform === "win32"
    , link = hard ? "link" : "symlink"
    , lp = hard ? path.resolve(me.dirname, me.linkpath) : me.linkpath

  // can only change the link path by clobbering
  // For hard links, let's just assume that's always the case, since
  // there's no good way to read them if we don't already know.
  if (hard) return clobber(me, lp, link)

  fs.readlink(me._path, function (er, p) {
    // only skip creation if it's exactly the same link
    if (p && p === lp) return finish(me)
    clobber(me, lp, link)
  })
}

function clobber (me, lp, link) {
  rimraf(me._path, function (er) {
    if (er) return me.error(er)
    create(me, lp, link)
  })
}

function create (me, lp, link) {
  fs[link](lp, me._path, function (er) {
    // if this is a hard link, and we're in the process of writing out a
    // directory, it's very possible that the thing we're linking to
    // doesn't exist yet (especially if it was intended as a symlink),
    // so swallow ENOENT errors here and just soldier in.
    // Additionally, an EPERM or EACCES can happen on win32 if it's trying
    // to make a link to a directory.  Again, just skip it.
    // A better solution would be to have fs.symlink be supported on
    // windows in some nice fashion.
    if (er) {
      if ((er.code === "ENOENT" ||
           er.code === "EACCES" ||
           er.code === "EPERM" ) && process.platform === "win32") {
        me.ready = true
        me.emit("ready")
        me.emit("end")
        me.emit("close")
        me.end = me._finish = function () {}
      } else return me.error(er)
    }
    finish(me)
  })
}

function finish (me) {
  me.ready = true
  me.emit("ready")
  if (me._ended && !me._finished) me._finish()
}

LinkWriter.prototype.end = function () {
  // console.error("LW finish in end")
  this._ended = true
  if (this.ready) {
    this._finished = true
    this._finish()
  }
}
<|endoftext|>


<commit_before>/// <reference path="../types/node-0.11.d.ts" />
var stream = require('stream');
var util = require('util');
var WritableStreamBuffer = require('stream-buffers').WritableStreamBuffer;

var M2TsStream = (function () {
	var DecideSyncUnitSizeCount = 3;
	util.inherits(M2TsStream, stream.Transform);
	var SyncByte = 0x47;
	function M2TsStream (unitSize, includePids, excluedPids) {
		stream.Transform.call(this);
		if (includePids != null) {
			this.enableInclude = true;
			this.includePids = includePids;
		} else if (excluedPids != null) {
			this.enableExclude = true;
			this.excludePids = excluedPids;
		}
		this.buffer = new WritableStreamBuffer();
		this.unitSize = unitSize || -1;
		this.syncByteOffsets = [];
		this.dataOffset = -1;
	}

	M2TsStream.prototype._transform = function (chunk, encoding, callback) {
		if (this.unitSize < 0) {
			var offset = this.buffer.size();
			for (var i = 0; i < chunk.length; i++) {
				if (chunk[i] === SyncByte) {
					this.syncByteOffsets.push(i + offset);
				}
			}

			this.unitSize = this.decideUnitSize(this.syncByteOffsets);
			this.buffer.write(chunk);

			if (this.unitSize > 0) {
				this.syncByteOffsets = [];
				if (this.dataOffset > 0) {
					this.buffer.getContents(this.dataOffset);
				}
			}
		} else {
			this.buffer.write(chunk);
		}

		while (this.unitSize > 0 && this.buffer.size() >= this.unitSize) {
			var tsPacket = this.buffer.getContents(this.unitSize);
			var pid = tsPacket.readUInt16BE(1) & 0x1fff;
			var push = true;
			if (this.enableInclude) {
				push = this.includePids.indexOf(pid) >= 0;
			} else if (this.enableExclude) {
				push = this.excludePids.indexOf(pid) < 0;
			}
			if (push) {
				this.push(tsPacket);
			}
		}

		callback();
	};

	M2TsStream.prototype.decideUnitSize = function (syncByteOffsets, readCount) {
		readCount = readCount || 0;
		if (syncByteOffsets.length - readCount < DecideSyncUnitSizeCount) {
			return -1;
		}

		var diffs = [];
		var syncByteOffset = syncByteOffsets[readCount];
		for (var i = readCount + 1; i < syncByteOffsets.length; i++) {
			diffs.push(syncByteOffsets[i] - syncByteOffset);
		}

		for (var i = 0; i < diffs.length; i++) {
			var diff = diffs[i];
			var found = true;
			for (var j = 1; j <= DecideSyncUnitSizeCount; j++) {
				if (syncByteOffsets.indexOf(syncByteOffset + diff * j) < 0) {
					found = false;
					break;
				}
			}

			if (found) {
				this.dataOffset = syncByteOffset;
				return diff;
			}
		}

		return this.decideUnitSize(syncByteOffsets, readCount + 1);
	}

	M2TsStream.prototype.include = function (args) {
		if (!Array.isArray(args)) {
			args = Array.prototype.slice.call(arguments);
		}

		var stream = new M2TsStream(this.unitSize, args, null);
		this.pipe(stream);
		return stream;
	}

	M2TsStream.prototype.exclude = function (args) {
		if (!Array.isArray(args)) {
			args = Array.prototype.slice.call(arguments);
		}

		var stream = new M2TsStream(this.unitSize, null, args);
		this.pipe(stream);
		return stream;
	}

	return M2TsStream;
})();

module.exports = M2TsStream;
<commit_msg>whereとparseを追加<commit_after>/// <reference path="../types/node-0.11.d.ts" />
var stream = require('stream');
var util = require('util');
var WritableStreamBuffer = require('stream-buffers').WritableStreamBuffer;
var M2TsPacket = require('./m2ts-packet.js');

var M2TsStream = (function () {
	var DecideSyncUnitSizeCount = 3;
	util.inherits(M2TsStream, stream.Transform);
	var SyncByte = 0x47;
	function M2TsStream (unitSize) {
		stream.Transform.call(this);

		this.enableParse = false;
		this.buffer = new WritableStreamBuffer();
		this.unitSize = unitSize || -1;
		this.syncByteOffsets = [];
		this.dataOffset = -1;
		this.predicate = null;
	}

	M2TsStream.prototype._transform = function (chunk, encoding, callback) {
		if (this._writableState.objectMode) {
			var push = true;
			if (this.predicate !== null) {
				push = this.predicate(chunk, chunk.pid);
			}
			if (push) {
				this.push(chunk);
			}
		} else {
			if (this.unitSize < 0) {
				var offset = this.buffer.size();
				for (var i = 0; i < chunk.length; i++) {
					if (chunk[i] === SyncByte) {
						this.syncByteOffsets.push(i + offset);
					}
				}

				this.unitSize = this.decideUnitSize(this.syncByteOffsets);
				this.buffer.write(chunk);

				if (this.unitSize > 0) {
					this.syncByteOffsets = [];
					if (this.dataOffset > 0) {
						this.buffer.getContents(this.dataOffset);
					}
				}
			} else {
				this.buffer.write(chunk);
			}

			while (this.unitSize > 0 && this.buffer.size() >= this.unitSize) {
				var rawTsPacket = this.buffer.getContents(this.unitSize);
				var pid = -1;
				var tsPacket = null;

				if (this.enableParse) {
					tsPacket = new M2TsPacket(rawTsPacket);
					pid = tsPacket.pid;
				} else {
					tsPacket = rawTsPacket;
					pid = tsPacket.readUInt16BE(1) & 0x1fff;
				}

				var push = true;
				if (this.predicate !== null) {
					push = this.predicate(tsPacket, pid);
				}

				if (push) {
					this.push(tsPacket);
				}
			}
		}

		callback();
	};

	M2TsStream.prototype.decideUnitSize = function (syncByteOffsets, readCount) {
		readCount = readCount || 0;
		if (syncByteOffsets.length - readCount < DecideSyncUnitSizeCount) {
			return -1;
		}

		var diffs = [];
		var syncByteOffset = syncByteOffsets[readCount];
		for (var i = readCount + 1; i < syncByteOffsets.length; i++) {
			diffs.push(syncByteOffsets[i] - syncByteOffset);
		}

		for (var i = 0; i < diffs.length; i++) {
			var diff = diffs[i];
			var found = true;
			for (var j = 1; j <= DecideSyncUnitSizeCount; j++) {
				if (syncByteOffsets.indexOf(syncByteOffset + diff * j) < 0) {
					found = false;
					break;
				}
			}

			if (found) {
				this.dataOffset = syncByteOffset;
				return diff;
			}
		}

		return this.decideUnitSize(syncByteOffsets, readCount + 1);
	};

	M2TsStream.prototype._setPredicate = function (predicate) {
		this.predicate = predicate;
	};

	M2TsStream.prototype.include = function (args) {
		if (!Array.isArray(args)) {
			args = Array.prototype.slice.call(arguments);
		}

		var stream = new M2TsStream(this.unitSize);
		stream._setObjectMode(this._readableState.objectMode, this._readableState.objectMode);
		stream._setPredicate(function (_, pid) {
			return args.indexOf(pid) >= 0;
		});
		return this.pipe(stream);
	};

	M2TsStream.prototype.exclude = function (args) {
		if (!Array.isArray(args)) {
			args = Array.prototype.slice.call(arguments);
		}

		var stream = new M2TsStream(this.unitSize);
		stream._setObjectMode(this._readableState.objectMode, this._readableState.objectMode);
		stream._setPredicate(function (_, pid) {
			return args.indexOf(pid) < 0;
		});
		return this.pipe(stream);
	};

	M2TsStream.prototype.where = function (predicate) {
		var stream = new M2TsStream(this.unitSize);
		stream._setObjectMode(this._readableState.objectMode, this._readableState.objectMode);
		stream._setPredicate(predicate);
		return this.pipe(stream);
	};

	M2TsStream.prototype._setObjectMode = function (readObjectMode, writeObjectMode) {
		this.enableParse = this._readableState.objectMode = readObjectMode;
		this._writableState.objectMode = writeObjectMode;
	};

	M2TsStream.prototype.parse = function () {
		var stream = new M2TsStream(this.unitSize);
		stream._setObjectMode(true, this.enableParse);
		return this.pipe(stream);
	};

	return M2TsStream;
})();

module.exports = M2TsStream;
<|endoftext|>


<commit_before>'use strict';

var utils = require('./utils');
var OPTIONAL_REGEX = /^optional!/;

function getRequestOpts(self, requestArgs, spec, overrideData) {
  // Extract spec values with defaults.
  var commandPath = typeof spec.path == 'function' ? spec.path
    : utils.makeURLInterpolator(spec.path || '');
  var requestMethod = (spec.method || 'GET').toUpperCase();
  var urlParams = spec.urlParams || [];
  var encode = spec.encode || function(data) {return data;};
  var host = spec.host;

  // Don't mutate args externally.
  var args = [].slice.call(requestArgs);

  // Generate and validate url params.
  var urlData = self.createUrlData();
  for (var i = 0, l = urlParams.length; i < l; ++i) {
    var path;

    // Note that we shift the args array after every iteration so this just
    // grabs the "next" argument for use as a URL parameter.
    var arg = args[0];

    var param = urlParams[i];

    var isOptional = OPTIONAL_REGEX.test(param);
    param = param.replace(OPTIONAL_REGEX, '');

    if (param == 'id' && typeof arg !== 'string') {
      path = self.createResourcePathWithSymbols(spec.path);
      throw new Error(
        'Stripe: "id" must be a string, but got: ' + typeof arg +
        ' (on API request to `' + requestMethod + ' ' + path + '`)'
      );
    }

    if (!arg) {
      if (isOptional) {
        urlData[param] = '';
        continue;
      }

      path = self.createResourcePathWithSymbols(spec.path);
      throw new Error(
        'Stripe: Argument "' + urlParams[i] + '" required, but got: ' + arg +
        ' (on API request to `' + requestMethod + ' ' + path + '`)'
      );
    }

    urlData[param] = args.shift();
  }

  // Pull request data and options (headers, auth) from args.
  var dataFromArgs = utils.getDataFromArgs(args);
  var data = encode(Object.assign(dataFromArgs, overrideData));
  var options = utils.getOptionsFromArgs(args);

  // Validate that there are no more args.
  if (args.length) {
    path = self.createResourcePathWithSymbols(spec.path);
    throw new Error(
      'Stripe: Unknown arguments (' + args + '). Did you mean to pass an options ' +
      'object? See https://github.com/stripe/stripe-node/wiki/Passing-Options.' +
      ' (on API request to ' + requestMethod + ' `' + path + '`)'
    );
  }

  var requestPath = self.createFullPath(commandPath, urlData);
  var headers = Object.assign(options.headers, spec.headers);

  if (spec.validator) {
    spec.validator(data, {headers: headers});
  }

  return {
    requestMethod: requestMethod,
    requestPath: requestPath,
    data: data,
    auth: options.auth,
    headers: headers,
    host: host,
  };
}

function makeRequest(self, requestArgs, spec, overrideData) {
  return new Promise(function(resolve, reject) {
    try {
      var opts = getRequestOpts(self, requestArgs, spec, overrideData);
    } catch (err) {
      reject(err);
      return;
    }

    function requestCallback(err, response) {
      if (err) {
        reject(err);
      } else {
        resolve(
          spec.transformResponseData ?
            spec.transformResponseData(response) :
            response
        );
      }
    }

    self._request(opts.requestMethod, opts.host, opts.requestPath, opts.data, opts.auth, {headers: opts.headers}, requestCallback);
  });
}

module.exports = makeRequest;
<commit_msg>Do not mutate data param in general (shallow)<commit_after>'use strict';

var utils = require('./utils');
var OPTIONAL_REGEX = /^optional!/;

function getRequestOpts(self, requestArgs, spec, overrideData) {
  // Extract spec values with defaults.
  var commandPath = typeof spec.path == 'function' ? spec.path
    : utils.makeURLInterpolator(spec.path || '');
  var requestMethod = (spec.method || 'GET').toUpperCase();
  var urlParams = spec.urlParams || [];
  var encode = spec.encode || function(data) {return data;};
  var host = spec.host;

  // Don't mutate args externally.
  var args = [].slice.call(requestArgs);

  // Generate and validate url params.
  var urlData = self.createUrlData();
  for (var i = 0, l = urlParams.length; i < l; ++i) {
    var path;

    // Note that we shift the args array after every iteration so this just
    // grabs the "next" argument for use as a URL parameter.
    var arg = args[0];

    var param = urlParams[i];

    var isOptional = OPTIONAL_REGEX.test(param);
    param = param.replace(OPTIONAL_REGEX, '');

    if (param == 'id' && typeof arg !== 'string') {
      path = self.createResourcePathWithSymbols(spec.path);
      throw new Error(
        'Stripe: "id" must be a string, but got: ' + typeof arg +
        ' (on API request to `' + requestMethod + ' ' + path + '`)'
      );
    }

    if (!arg) {
      if (isOptional) {
        urlData[param] = '';
        continue;
      }

      path = self.createResourcePathWithSymbols(spec.path);
      throw new Error(
        'Stripe: Argument "' + urlParams[i] + '" required, but got: ' + arg +
        ' (on API request to `' + requestMethod + ' ' + path + '`)'
      );
    }

    urlData[param] = args.shift();
  }

  // Pull request data and options (headers, auth) from args.
  var dataFromArgs = utils.getDataFromArgs(args);
  var data = encode(Object.assign({}, dataFromArgs, overrideData));
  var options = utils.getOptionsFromArgs(args);

  // Validate that there are no more args.
  if (args.length) {
    path = self.createResourcePathWithSymbols(spec.path);
    throw new Error(
      'Stripe: Unknown arguments (' + args + '). Did you mean to pass an options ' +
      'object? See https://github.com/stripe/stripe-node/wiki/Passing-Options.' +
      ' (on API request to ' + requestMethod + ' `' + path + '`)'
    );
  }

  var requestPath = self.createFullPath(commandPath, urlData);
  var headers = Object.assign(options.headers, spec.headers);

  if (spec.validator) {
    spec.validator(data, {headers: headers});
  }

  return {
    requestMethod: requestMethod,
    requestPath: requestPath,
    data: data,
    auth: options.auth,
    headers: headers,
    host: host,
  };
}

function makeRequest(self, requestArgs, spec, overrideData) {
  return new Promise(function(resolve, reject) {
    try {
      var opts = getRequestOpts(self, requestArgs, spec, overrideData);
    } catch (err) {
      reject(err);
      return;
    }

    function requestCallback(err, response) {
      if (err) {
        reject(err);
      } else {
        resolve(
          spec.transformResponseData ?
            spec.transformResponseData(response) :
            response
        );
      }
    }

    self._request(opts.requestMethod, opts.host, opts.requestPath, opts.data, opts.auth, {headers: opts.headers}, requestCallback);
  });
}

module.exports = makeRequest;
<|endoftext|>


<commit_before>/** internal
 *  class Base
 *
 *  Base class for [[Environment]] and [[Index]].
 *
 *
 *  ##### INCLUDES
 *
 *  - [[Engines]]
 *  - [[Mime]]
 *  - [[Processing]]
 *  - [[Paths]]
 **/

'use strict';

// stdlib
var fs      = require('fs');
var path    = require('path');
var crypto  = require('crypto');

// 3rd-party
var _ = require('lodash');

// internal
var getter          = require('./common').getter;
var prop            = require('./common').prop;
var mixin           = require('./common').mixin;
var isAbsolute      = require('./common').isAbsolute;
var VERSION         = require('./version');
var AssetAttributes = require('./asset_attributes');
var StaticAsset     = require('./assets/static');
var ProcessedAsset  = require('./assets/processed');
var BundledAsset    = require('./assets/bundled');

////////////////////////////////////////////////////////////////////////////////

/**
 *  new Base()
 **/
var Base = module.exports = function Base() {};

mixin(Base.prototype, require('./helpers/paths'));
mixin(Base.prototype, require('./helpers/mime'));
mixin(Base.prototype, require('./helpers/caching'));
mixin(Base.prototype, require('./helpers/processing'));
mixin(Base.prototype, require('./helpers/compressing'));
mixin(Base.prototype, require('./helpers/configuring'));
mixin(Base.prototype, require('./helpers/engines'));

// helper that defines property which fires expireIndex()
// each time it gets changed
function attr_with_expire_index(name, value) {
  var __name__ = '__' + name + '__';

  // set underlying value
  prop(Base.prototype, __name__, value, {writable: true});

  // provide getters/setter
  Object.defineProperty(Base.prototype, name, {
    get: function () {
      return this[__name__];
    },
    set: function (val) {
      this.expireIndex();
      this[__name__] = val;
    }
  });
}

/**
 *  Base#cache -> Mixed
 *
 *  Cache backend.
 *
 *  Default: `null`.
 **/
attr_with_expire_index('cache', null);

/**
 *  Base#digestAlgorithm -> String
 *
 *  Digest algorithm: `sha1` or `md5`.
 *  See Node manual on `crypto` module.
 *
 *  Default: `md5`.
 **/
attr_with_expire_index('digestAlgorithm', 'md5');

/**
 *  Base#version -> String
 *
 *  Environment version.
 *
 *      environment.version = '2.0'
 **/
attr_with_expire_index('version', '');

/**
 *  Base#digest -> crypto.Hash
 *
 *  Returns a `crypto.Hash` instance for the `Environment`.
 *
 *  This value serves two purposes. If two `Environment`s have the
 *  same digest value they can be treated as equal. This is more
 *  useful for comparing environment states between processes rather
 *  than in the same. Two equal `Environment`s can share the same
 *  cached assets.
 *
 *  The value also provides a seed digest for all `Asset` digests.
 *  Any change in the environment digest will affect all of its assets.
 **/
getter(Base.prototype, 'digest', function () {
  // Do not cache, so the caller can safely mutate it with `.update`
  var digest = crypto.createHash(this.digestAlgorithm);

  // Mixin Mincer release version and custom environment version.
  // So any new releases will affect all your assets.
  digest.update(VERSION,      'utf8');
  digest.update(this.version, 'utf8');

  return digest;
});

// helper that overrides defined method `name` with wrapper that expireIndex()
// and calls `func` when provided before calling original method
function func_proxy_with_expire_index(name, func) {
  var orig = Base.prototype[name];

  Base.prototype[name] = function () {
    this.expireIndex();
    if (func) {
      func.apply(this, arguments);
    }
    orig.apply(this, arguments);
  };
}

//
// override [[Paths]] mixin methods
//

func_proxy_with_expire_index('prependPath');
func_proxy_with_expire_index('appendPath');
func_proxy_with_expire_index('clearPaths');

//
// override [[Mime]] mixin methods
//

func_proxy_with_expire_index('registerMimeType', function (mimeType, ext) {
  this.__trail__.extensions.append(ext);
});

//
// override [[Engines]] mixin methods
//

func_proxy_with_expire_index('registerEngine', function (ext, klass) {
  this.addEngineToTrail(ext, klass);
});

//
// override [[Processing]] mixin methods
//

func_proxy_with_expire_index('registerPreprocessor');
func_proxy_with_expire_index('registerPostprocessor');
func_proxy_with_expire_index('registerBundleProcessor');
func_proxy_with_expire_index('unregisterPreprocessor');
func_proxy_with_expire_index('unregisterPostprocessor');
func_proxy_with_expire_index('unregisterBundleProcessor');

/**
 *  Base#resolve(logicalPath[, options = {}[, fn]]) -> String
 *  - logicalPath (String)
 *  - options (Object)
 *  - fn (Function)
 *
 *  Finds the expanded real path for a given logical path by
 *  searching the environment's paths.
 *
 *      env.resolve("application.js")
 *      # => "/path/to/app/javascripts/application.js.coffee"
 *
 *  An Error with `code = 'FileNotFound'` is raised if the file does not exist.
 **/
Base.prototype.resolve = function (logicalPath, options, fn) {
  var err, resolved, search;

  if (fn) {
    search = this.attributesFor(logicalPath).searchPaths;
    return this.__trail__.find(search, options, function (pathname) {
      var bower, extname, mainfile;

      if (!_.contains(['component.json', 'bower.json'], path.basename(pathname))) {
        return fn(pathname);
      }

      bower = require(pathname);

      if (_.isString(bower.main)) {
        return fn(path.join(path.dirname(pathname), bower.main));
      }

      if (_.isArray(bower.main)) {
        extname = path.extname(pathname);

        while (bower.main.length) {
          mainfile = bower.main.shift();

          if ('' === extname || extname === path.extname(mainfile)) {
            return fn(path.join(path.dirname(pathname), mainfile));
          }
        }
      }

      return;
    });
  }

  resolved = this.resolve(logicalPath, options, function (pathname) {
    return pathname;
  });

  if (!resolved) {
    err = new Error("couldn't find file '" + logicalPath + "'");
    err.code = 'FileNotFound';
    throw err;
  }

  return resolved;
};

/**
 *  Base#entries(pathname) -> Array
 *  - pathname (String)
 *
 *  Proxy to `Hike.Trail#entries`. Works like `fs.readdirSync`.
 *  Subclasses may cache this method.
 **/
Base.prototype.entries = function (pathname) {
  return this.__trail__.entries(pathname);
};

/**
 *  Base#stat(pathname) -> fs.Stats
 *  - pathname (String)
 *
 *  Proxy to `Hike.Trail#stat`. Works like `fs.statSync`.
 *  Subclasses may cache this method.
 **/
Base.prototype.stat = function (pathname) {
  return this.__trail__.stat(pathname);
};

/**
 *  Base#getFileDigest(pathname) -> String
 *  - pathname (String)
 *
 *  Read and compute digest of filename.
 *  Subclasses may cache this method.
 **/
Base.prototype.getFileDigest = function (pathname) {
  var stat = this.stat(pathname);

  if (stat && stat.isDirectory()) {
    // If directory, digest the list of filenames
    return this.digest.update(this.entries(pathname).join(',')).digest('hex');
  }

  // If file, digest the contents
  return this.digest.update(fs.readFileSync(pathname)).digest('hex');
};

/** internal
 *  Base#attributesFor(pathname) -> AssetAttributes
 *  - pathname (String)
 *
 *  Returns a `AssetAttributes` for `pathname`
 **/
Base.prototype.attributesFor = function (pathname) {
  return new AssetAttributes(this, pathname);
};

/** internal
 *  Base#contentTypeOf(pathname) -> String
 *  - pathname (String)
 *
 *  Returns content type of `pathname`
 **/
Base.prototype.contentTypeOf = function (pathname) {
  return this.attributesFor(pathname).contentType;
};

/**
 *  Base#findAsset(pathname[, options = {}]) -> Asset|Null
 *  - pathname (String)
 *  - options (Object)
 *
 *  Find asset by logical path or expanded path.
 **/
Base.prototype.findAsset = function (pathname, options) {
  var logical_path = pathname, expanded_path;

  if (isAbsolute(pathname)) {
    if (!this.stat(pathname)) {
      return null;
    }

    logical_path = this.attributesFor(pathname).logicalPath;
  } else {
    try {
      pathname = this.resolve(logical_path);

      if ('' === path.extname(logical_path)) {
        expanded_path = this.attributesFor(pathname).logicalPath;
        logical_path += path.extname(expanded_path);
      }
    } catch (err) {
      if ('FileNotFound' === err.code) {
        return null;
      }

      throw err;
    }
  }

  return this.buildAsset(logical_path, pathname, options);
};

/**
 *  Base#eachEntry(root, iterator) -> Void
 *  - root (String)
 *  - iterator (Function)
 *
 *  Calls `iterator` on each found file or directory in alphabetical order:
 *
 *      env.eachEntry('/some/path', function (entry) {
 *        console.log(entry);
 *      });
 *      // -> "/some/path/a"
 *      // -> "/some/path/a/b.txt"
 *      // -> "/some/path/a/c.txt"
 *      // -> "/some/path/b.txt"
 **/
Base.prototype.eachEntry = function (root, iterator) {
  var self = this, paths = [];

  this.entries(root).forEach(function (filename) {
    var pathname  = path.join(root, filename),
        stats     = self.stat(pathname);

    if (!stats) {
      // File not found - silently skip it.
      // It might happen only if we got "broken" symlink in real life.
      // See https://github.com/nodeca/mincer/issues/18
      return;
    }

    paths.push(pathname);

    if (stats.isDirectory()) {
      self.eachEntry(pathname, function (subpath) {
        paths.push(subpath);
      });
    }
  });

  paths.sort().forEach(iterator);
};

/**
 *  Base#eachFile(iterator) -> Void
 *  - iterator (Function)
 *
 *  Calls `iterator` for each file found within all registered paths.
 **/
Base.prototype.eachFile = function (iterator) {
  var self = this;

  this.paths.forEach(function (root) {
    self.eachEntry(root, function (pathname) {
      if (!self.stat(pathname).isDirectory()) {
        iterator(pathname);
      }
    });
  });
};

// Returns true if there were no filters, or `filename` matches at least one
function matches_filter(filters, logicalPath, filename) {
  if (0 === filters.length) {
    return true;
  }

  return _.any(filters, function (filter) {
    if (_.isRegExp(filter)) {
      return filter.test(logicalPath);
    }

    if (_.isFunction(filter)) {
      return filter(logicalPath, filename);
    }

    // prepare string to become RegExp.
    // mimics shell's globbing
    filter = filter.toString().replace(/\*\*|\*|\?|\\.|\./g, function (m) {
      if ('*' === m[0]) {
        return "**" === m ? ".+?" : "[^/]+?";
      }

      if ('?' === m[0]) {
        return "[^/]?";
      }

      if ('.' === m[0]) {
        return "\\.";
      }

      // handle `\\.` part
      return m;
    });

    // prepare RegExp
    filter = new RegExp('^' + filter + '$');
    return filter.test(logicalPath);
  });
}

// Returns logicalPath for `filename` if it mtches given filters
function logical_path_for_filename(self, filename, filters) {
  var logical_path = self.attributesFor(filename).logicalPath;

  if (matches_filter(filters, logical_path, filename)) {
    return logical_path;
  }

  // If filename is an index file, retest with alias
  if ('index' === path.basename(filename).split('.').shift()) {
    logical_path = logical_path.replace(/\/index\./, '.');
    if (matches_filter(filters, logical_path, filename)) {
      return logical_path;
    }
  }
}

/**
 *  Base#eachLogicalPath(filters, iterator) -> Void
 *  - filters (Array)
 *  - iterator (Function)
 *
 *  Calls `iterator` on each found logical path (once per unique path) that
 *  matches at least one of the given filters.
 *
 *  Each filter might be a `String`, `RegExp` or a `Function`.
 **/
Base.prototype.eachLogicalPath = function (filters, iterator) {
  var self = this, files = {};

  this.eachFile(function (filename) {
    var logical_path = logical_path_for_filename(self, filename, filters);
    if (logical_path && !files[logical_path]) {
      iterator(logical_path, filename);
      files[logical_path] = true;
    }
  });
};

// circular call  protection helper.
// keeps array of required pathnames until the function
// that originated protection finishes it's execution
var circular_calls = null;

function circular_call_protection(pathname, callback) {
  var reset = (null === circular_calls),
      calls = circular_calls || (circular_calls = []);

  try {
    if (0 <= calls.indexOf(pathname)) {
      throw new Error("Circular dependency detected: " + pathname +
                      " has already been required");
    }

    calls.push(pathname);
    return callback();
  } catch (err) {
    if (reset) {
      circular_calls = null;
    }

    throw err;
  }
}

// creates instance of [[StaticAsset]], [[BundledAsset]] or [[ProcessedAsset]]
Base.prototype.buildAsset = function (logicalPath, pathname, options) {
  var self = this;

  options = options || {};

  // If there are any processors to run on the pathname, use
  // `BundledAsset`. Otherwise use `StaticAsset` and treat is as binary.

  if (0 === this.attributesFor(pathname).processors.length) {
    return new StaticAsset(this.index, logicalPath, pathname);
  }

  if (options.bundle) {
    return new BundledAsset(this.index, logicalPath, pathname);
  }

  return circular_call_protection(pathname, function () {
    return new ProcessedAsset(self.index, logicalPath, pathname);
  });
};

// Returns cache key for given `pathname` based on options
Base.prototype.cacheKeyFor = function (pathname, options) {
  return pathname + String(options.bundle ? 1 : 0);
};
<commit_msg>Fixes circular dependency protection<commit_after>/** internal
 *  class Base
 *
 *  Base class for [[Environment]] and [[Index]].
 *
 *
 *  ##### INCLUDES
 *
 *  - [[Engines]]
 *  - [[Mime]]
 *  - [[Processing]]
 *  - [[Paths]]
 **/

'use strict';

// stdlib
var fs      = require('fs');
var path    = require('path');
var crypto  = require('crypto');

// 3rd-party
var _ = require('lodash');

// internal
var getter          = require('./common').getter;
var prop            = require('./common').prop;
var mixin           = require('./common').mixin;
var isAbsolute      = require('./common').isAbsolute;
var VERSION         = require('./version');
var AssetAttributes = require('./asset_attributes');
var StaticAsset     = require('./assets/static');
var ProcessedAsset  = require('./assets/processed');
var BundledAsset    = require('./assets/bundled');

////////////////////////////////////////////////////////////////////////////////

/**
 *  new Base()
 **/
var Base = module.exports = function Base() {};

mixin(Base.prototype, require('./helpers/paths'));
mixin(Base.prototype, require('./helpers/mime'));
mixin(Base.prototype, require('./helpers/caching'));
mixin(Base.prototype, require('./helpers/processing'));
mixin(Base.prototype, require('./helpers/compressing'));
mixin(Base.prototype, require('./helpers/configuring'));
mixin(Base.prototype, require('./helpers/engines'));

// helper that defines property which fires expireIndex()
// each time it gets changed
function attr_with_expire_index(name, value) {
  var __name__ = '__' + name + '__';

  // set underlying value
  prop(Base.prototype, __name__, value, {writable: true});

  // provide getters/setter
  Object.defineProperty(Base.prototype, name, {
    get: function () {
      return this[__name__];
    },
    set: function (val) {
      this.expireIndex();
      this[__name__] = val;
    }
  });
}

/**
 *  Base#cache -> Mixed
 *
 *  Cache backend.
 *
 *  Default: `null`.
 **/
attr_with_expire_index('cache', null);

/**
 *  Base#digestAlgorithm -> String
 *
 *  Digest algorithm: `sha1` or `md5`.
 *  See Node manual on `crypto` module.
 *
 *  Default: `md5`.
 **/
attr_with_expire_index('digestAlgorithm', 'md5');

/**
 *  Base#version -> String
 *
 *  Environment version.
 *
 *      environment.version = '2.0'
 **/
attr_with_expire_index('version', '');

/**
 *  Base#digest -> crypto.Hash
 *
 *  Returns a `crypto.Hash` instance for the `Environment`.
 *
 *  This value serves two purposes. If two `Environment`s have the
 *  same digest value they can be treated as equal. This is more
 *  useful for comparing environment states between processes rather
 *  than in the same. Two equal `Environment`s can share the same
 *  cached assets.
 *
 *  The value also provides a seed digest for all `Asset` digests.
 *  Any change in the environment digest will affect all of its assets.
 **/
getter(Base.prototype, 'digest', function () {
  // Do not cache, so the caller can safely mutate it with `.update`
  var digest = crypto.createHash(this.digestAlgorithm);

  // Mixin Mincer release version and custom environment version.
  // So any new releases will affect all your assets.
  digest.update(VERSION,      'utf8');
  digest.update(this.version, 'utf8');

  return digest;
});

// helper that overrides defined method `name` with wrapper that expireIndex()
// and calls `func` when provided before calling original method
function func_proxy_with_expire_index(name, func) {
  var orig = Base.prototype[name];

  Base.prototype[name] = function () {
    this.expireIndex();
    if (func) {
      func.apply(this, arguments);
    }
    orig.apply(this, arguments);
  };
}

//
// override [[Paths]] mixin methods
//

func_proxy_with_expire_index('prependPath');
func_proxy_with_expire_index('appendPath');
func_proxy_with_expire_index('clearPaths');

//
// override [[Mime]] mixin methods
//

func_proxy_with_expire_index('registerMimeType', function (mimeType, ext) {
  this.__trail__.extensions.append(ext);
});

//
// override [[Engines]] mixin methods
//

func_proxy_with_expire_index('registerEngine', function (ext, klass) {
  this.addEngineToTrail(ext, klass);
});

//
// override [[Processing]] mixin methods
//

func_proxy_with_expire_index('registerPreprocessor');
func_proxy_with_expire_index('registerPostprocessor');
func_proxy_with_expire_index('registerBundleProcessor');
func_proxy_with_expire_index('unregisterPreprocessor');
func_proxy_with_expire_index('unregisterPostprocessor');
func_proxy_with_expire_index('unregisterBundleProcessor');

/**
 *  Base#resolve(logicalPath[, options = {}[, fn]]) -> String
 *  - logicalPath (String)
 *  - options (Object)
 *  - fn (Function)
 *
 *  Finds the expanded real path for a given logical path by
 *  searching the environment's paths.
 *
 *      env.resolve("application.js")
 *      # => "/path/to/app/javascripts/application.js.coffee"
 *
 *  An Error with `code = 'FileNotFound'` is raised if the file does not exist.
 **/
Base.prototype.resolve = function (logicalPath, options, fn) {
  var err, resolved, search;

  if (fn) {
    search = this.attributesFor(logicalPath).searchPaths;
    return this.__trail__.find(search, options, function (pathname) {
      var bower, extname, mainfile;

      if (!_.contains(['component.json', 'bower.json'], path.basename(pathname))) {
        return fn(pathname);
      }

      bower = require(pathname);

      if (_.isString(bower.main)) {
        return fn(path.join(path.dirname(pathname), bower.main));
      }

      if (_.isArray(bower.main)) {
        extname = path.extname(pathname);

        while (bower.main.length) {
          mainfile = bower.main.shift();

          if ('' === extname || extname === path.extname(mainfile)) {
            return fn(path.join(path.dirname(pathname), mainfile));
          }
        }
      }

      return;
    });
  }

  resolved = this.resolve(logicalPath, options, function (pathname) {
    return pathname;
  });

  if (!resolved) {
    err = new Error("couldn't find file '" + logicalPath + "'");
    err.code = 'FileNotFound';
    throw err;
  }

  return resolved;
};

/**
 *  Base#entries(pathname) -> Array
 *  - pathname (String)
 *
 *  Proxy to `Hike.Trail#entries`. Works like `fs.readdirSync`.
 *  Subclasses may cache this method.
 **/
Base.prototype.entries = function (pathname) {
  return this.__trail__.entries(pathname);
};

/**
 *  Base#stat(pathname) -> fs.Stats
 *  - pathname (String)
 *
 *  Proxy to `Hike.Trail#stat`. Works like `fs.statSync`.
 *  Subclasses may cache this method.
 **/
Base.prototype.stat = function (pathname) {
  return this.__trail__.stat(pathname);
};

/**
 *  Base#getFileDigest(pathname) -> String
 *  - pathname (String)
 *
 *  Read and compute digest of filename.
 *  Subclasses may cache this method.
 **/
Base.prototype.getFileDigest = function (pathname) {
  var stat = this.stat(pathname);

  if (stat && stat.isDirectory()) {
    // If directory, digest the list of filenames
    return this.digest.update(this.entries(pathname).join(',')).digest('hex');
  }

  // If file, digest the contents
  return this.digest.update(fs.readFileSync(pathname)).digest('hex');
};

/** internal
 *  Base#attributesFor(pathname) -> AssetAttributes
 *  - pathname (String)
 *
 *  Returns a `AssetAttributes` for `pathname`
 **/
Base.prototype.attributesFor = function (pathname) {
  return new AssetAttributes(this, pathname);
};

/** internal
 *  Base#contentTypeOf(pathname) -> String
 *  - pathname (String)
 *
 *  Returns content type of `pathname`
 **/
Base.prototype.contentTypeOf = function (pathname) {
  return this.attributesFor(pathname).contentType;
};

/**
 *  Base#findAsset(pathname[, options = {}]) -> Asset|Null
 *  - pathname (String)
 *  - options (Object)
 *
 *  Find asset by logical path or expanded path.
 **/
Base.prototype.findAsset = function (pathname, options) {
  var logical_path = pathname, expanded_path;

  if (isAbsolute(pathname)) {
    if (!this.stat(pathname)) {
      return null;
    }

    logical_path = this.attributesFor(pathname).logicalPath;
  } else {
    try {
      pathname = this.resolve(logical_path);

      if ('' === path.extname(logical_path)) {
        expanded_path = this.attributesFor(pathname).logicalPath;
        logical_path += path.extname(expanded_path);
      }
    } catch (err) {
      if ('FileNotFound' === err.code) {
        return null;
      }

      throw err;
    }
  }

  return this.buildAsset(logical_path, pathname, options);
};

/**
 *  Base#eachEntry(root, iterator) -> Void
 *  - root (String)
 *  - iterator (Function)
 *
 *  Calls `iterator` on each found file or directory in alphabetical order:
 *
 *      env.eachEntry('/some/path', function (entry) {
 *        console.log(entry);
 *      });
 *      // -> "/some/path/a"
 *      // -> "/some/path/a/b.txt"
 *      // -> "/some/path/a/c.txt"
 *      // -> "/some/path/b.txt"
 **/
Base.prototype.eachEntry = function (root, iterator) {
  var self = this, paths = [];

  this.entries(root).forEach(function (filename) {
    var pathname  = path.join(root, filename),
        stats     = self.stat(pathname);

    if (!stats) {
      // File not found - silently skip it.
      // It might happen only if we got "broken" symlink in real life.
      // See https://github.com/nodeca/mincer/issues/18
      return;
    }

    paths.push(pathname);

    if (stats.isDirectory()) {
      self.eachEntry(pathname, function (subpath) {
        paths.push(subpath);
      });
    }
  });

  paths.sort().forEach(iterator);
};

/**
 *  Base#eachFile(iterator) -> Void
 *  - iterator (Function)
 *
 *  Calls `iterator` for each file found within all registered paths.
 **/
Base.prototype.eachFile = function (iterator) {
  var self = this;

  this.paths.forEach(function (root) {
    self.eachEntry(root, function (pathname) {
      if (!self.stat(pathname).isDirectory()) {
        iterator(pathname);
      }
    });
  });
};

// Returns true if there were no filters, or `filename` matches at least one
function matches_filter(filters, logicalPath, filename) {
  if (0 === filters.length) {
    return true;
  }

  return _.any(filters, function (filter) {
    if (_.isRegExp(filter)) {
      return filter.test(logicalPath);
    }

    if (_.isFunction(filter)) {
      return filter(logicalPath, filename);
    }

    // prepare string to become RegExp.
    // mimics shell's globbing
    filter = filter.toString().replace(/\*\*|\*|\?|\\.|\./g, function (m) {
      if ('*' === m[0]) {
        return "**" === m ? ".+?" : "[^/]+?";
      }

      if ('?' === m[0]) {
        return "[^/]?";
      }

      if ('.' === m[0]) {
        return "\\.";
      }

      // handle `\\.` part
      return m;
    });

    // prepare RegExp
    filter = new RegExp('^' + filter + '$');
    return filter.test(logicalPath);
  });
}

// Returns logicalPath for `filename` if it mtches given filters
function logical_path_for_filename(self, filename, filters) {
  var logical_path = self.attributesFor(filename).logicalPath;

  if (matches_filter(filters, logical_path, filename)) {
    return logical_path;
  }

  // If filename is an index file, retest with alias
  if ('index' === path.basename(filename).split('.').shift()) {
    logical_path = logical_path.replace(/\/index\./, '.');
    if (matches_filter(filters, logical_path, filename)) {
      return logical_path;
    }
  }
}

/**
 *  Base#eachLogicalPath(filters, iterator) -> Void
 *  - filters (Array)
 *  - iterator (Function)
 *
 *  Calls `iterator` on each found logical path (once per unique path) that
 *  matches at least one of the given filters.
 *
 *  Each filter might be a `String`, `RegExp` or a `Function`.
 **/
Base.prototype.eachLogicalPath = function (filters, iterator) {
  var self = this, files = {};

  this.eachFile(function (filename) {
    var logical_path = logical_path_for_filename(self, filename, filters);
    if (logical_path && !files[logical_path]) {
      iterator(logical_path, filename);
      files[logical_path] = true;
    }
  });
};

// circular call  protection helper.
// keeps array of required pathnames until the function
// that originated protection finishes it's execution
var circular_calls = null;

function circular_call_protection(pathname, callback) {
  var reset = (null === circular_calls),
      calls = circular_calls || (circular_calls = []);

  try {
    if (0 <= calls.indexOf(pathname)) {
      throw new Error("Circular dependency detected: " + pathname +
                      " has already been required");
    }

    calls.push(pathname);
    return callback();
  } finally {
    if (reset) {
      circular_calls = null;
    }
  }
}

// creates instance of [[StaticAsset]], [[BundledAsset]] or [[ProcessedAsset]]
Base.prototype.buildAsset = function (logicalPath, pathname, options) {
  var self = this;

  options = options || {};

  // If there are any processors to run on the pathname, use
  // `BundledAsset`. Otherwise use `StaticAsset` and treat is as binary.

  if (0 === this.attributesFor(pathname).processors.length) {
    return new StaticAsset(this.index, logicalPath, pathname);
  }

  if (options.bundle) {
    return new BundledAsset(this.index, logicalPath, pathname);
  }

  return circular_call_protection(pathname, function () {
    return new ProcessedAsset(self.index, logicalPath, pathname);
  });
};

// Returns cache key for given `pathname` based on options
Base.prototype.cacheKeyFor = function (pathname, options) {
  return pathname + String(options.bundle ? 1 : 0);
};
<|endoftext|>


<commit_before>'use strict';

const underscore = require('underscore');
const uuid = require('cassandra-uuid').TimeUuid;
const HTTPError = require('./util').HTTPError;
const mUtil = {};

mUtil.CONTENT_TYPES = {
    mobileSections: { name: 'mobile-sections', version: '0.9.1' },
    definition: { name: 'definition', version: '0.7.1' },

    random: { name: 'random', version: '0.6.0' },

    announcements: { name: 'announcements', version: '0.1.0' },

    onthisday: { name: 'onthisday', version: '0.1.0' },

    unpublished: { name: 'unpublished', version: '0.0.0' }
};

mUtil.setContentType = function(res, spec) {
    if (!spec.name || !spec.version) {
        throw new HTTPError({
            status: 500,
            type: 'invalid_content_type',
            title: 'Only use the allowed content-types',
            detail: `${spec.name}/${spec.version} is not an allowed content-type!`
        });
    }

    res.type(`application/json; charset=utf-8; profile="https://www.mediawiki.org/wiki/Specs/${spec.name}/${spec.version}"`);
};

/**
 * @returns true if val is null, undefined, an empty object, an empty array, or
 *          an empty string.
 */
mUtil.isEmpty = function(val) {
    return !underscore.isNumber(val)
        && !underscore.isBoolean(val)
        && underscore.isEmpty(val);
};

mUtil.isNonempty = underscore.negate(mUtil.isEmpty);

/**
 * @param [fallback]
 * @returns val if nonempty, else fallback.
*/
mUtil.defaultVal = function(val, fallback) {
    return underscore.isEmpty(val) ? fallback : val;
};

/**
 * @returns val less empty elements.
*/
mUtil.filterEmpty = function(val) {
    if (Array.isArray(val)) {
        return val.map(mUtil.filterEmpty).filter(mUtil.isNonempty);
    }
    if (underscore.isObject(val)) {
        return underscore.pick(underscore.mapObject(val, mUtil.filterEmpty), mUtil.isNonempty);
    }
    return val;
};

/**
 * Sets the ETag header on the response objecti, comprised of the revision ID and
 * the time UUID. If the latter is not given, the current time stamp is used to
 * generate it.
 *
 * @param {!Object}  response the HTTPResponse object on which to set the header
 * @param {?number} revision the revision integer ID to use
 * @param {?string}  tid      the time UUID to use; optional
 */
mUtil.setETag = function(response, revision, tid) {
    // we want to bail out if the revision hasn't been supplied, except
    // in the case revision === 0 because 0 is actually a valid rev_id
    if (!revision && revision !== 0) {
        return;
    }
    if (!tid) {
        tid = uuid.now().toString();
    }
    response.set('etag', `"${revision}/${tid}"`);
};

/**
 * Convert mobile to canonical domain,
 * e.g., 'en.m.wikipedia.org' => 'en.wikipedia.org'
 */
mUtil.mobileToCanonical = function(domain) {
    return domain.replace('.m.', '.');
};

/**
 * Remove the top-level domain from a domain string, e.g., 'en.wikipedia.org' ->
 * 'en.wikipedia'.
 */
mUtil.removeTLD = function(domain) {
    return domain.split('.').slice(0,2).join('.');
};

/**
 * Get the language of the wiki base don the domain name.
 * Example: 'en.wikipedia.org' -> 'en'.
 */
mUtil.getLanguageFromDomain = function(domain) {
    return domain.split('.')[0];
};

mUtil.isEnglishWikipedia = function(domain) {
    return (domain === 'en.wikipedia.org' || domain === 'en.wikipedia.beta.wmflabs.org');
};

mUtil.removeFragment = function(href) {
    if (href.indexOf('#') > -1) {
        return href.substring(0, href.indexOf('#'));
    }
    return href;
};

mUtil.removeLinkPrefix = function(href) {
    return href.replace(/^\.\//, '');
};

mUtil.extractDbTitleFromAnchor = function(anchor) {
    return anchor && mUtil.removeFragment(mUtil.removeLinkPrefix(anchor.getAttribute('href')));
};

// Merge two arrays of objects by the specified property.
// Stolen from https://jsfiddle.net/guya/eAWKR/.
mUtil.mergeByProp = function(arr1, arr2, prop, pushIfKeyNotFound) {
    if (!arr1 || !arr2) {
        return;
    }

    arr2.forEach((arr2obj) => {
        const arr1obj = arr1.find((arr1obj) => {
            return arr1obj[prop] === arr2obj[prop];
        });

        // If the object already exists, extend it with the new values from
        // arr2, otherwise conditionally add the new object to arr1.
        if (arr1obj) {
            Object.assign(arr1obj, arr2obj);
        } else if (pushIfKeyNotFound) {
            arr1.push(arr2obj);
        }
    });
};

/**
 * Takes an array of objects and makes the specified changes to the keys of each
 * member object.
 *
 * E.g., adjustMemberKeys(arr, ['to', 'from'], ['to', 'from'], ...)
 *
 * @param {!Array}  arr      an array of objects that will receive the change
 * pairs passed in as additional params
 */
mUtil.adjustMemberKeys = function(arr) {
    for (let i = 0, n = arr.length; i < n; i++) {
        for (let j = 1, m = arguments.length; j < m; j++) {
            if (arr[i][arguments[j][1]]) {
                arr[i][arguments[j][0]] = arr[i][arguments[j][1]];
                delete arr[i][arguments[j][1]];
            }
        }
    }
};

/**
 * Takes an array of objects and, for each object, creates the specified key (if
 * not already present) with the same value as the specified source key for each
 * change pair passed in as an additional parameter.
 *
 * E.g., fillInMemberKeys(arr, ['to', 'from'], ['to', 'from'], ...)
 *
 * @param {!Array}  arr      an array of objects that will receive the change
 * pairs passed in as additional params
 */
mUtil.fillInMemberKeys = function(arr) {
    for (let i = 0, n = arr.length; i < n; i++) {
        for (let j = 1, m = arguments.length; j < m; j++) {
            if (!arr[i][arguments[j][0]]) {
                arr[i][arguments[j][0]] = arr[i][arguments[j][1]];
            }
        }
    }
};

mUtil.getRbPageSummaryUrl = function(restbaseTpl, domain, title) {
    const request = restbaseTpl.expand({
        request: {
            params: {
                domain,
                path: `page/summary/${encodeURIComponent(title)}` },
        }
    });
    return request.uri;
};

mUtil.throw404 = function(message) {
    throw new HTTPError({
        status: 404,
        type: 'not_found',
        title: 'Not found',
        detail: message
    });
};

/* jslint bitwise: true */
/* eslint no-bitwise: ["error", { "allow": ["<<"] }] */
mUtil.hashCode = function(string) {
    return string.split('').reduce((prevHash, currVal) =>
       ((prevHash << 5) - prevHash) + currVal.charCodeAt(0), 0);
};

module.exports = mUtil;
<commit_msg>On this day: bump version<commit_after>'use strict';

const underscore = require('underscore');
const uuid = require('cassandra-uuid').TimeUuid;
const HTTPError = require('./util').HTTPError;
const mUtil = {};

mUtil.CONTENT_TYPES = {
    mobileSections: { name: 'mobile-sections', version: '0.9.1' },
    definition: { name: 'definition', version: '0.7.1' },

    random: { name: 'random', version: '0.6.0' },

    announcements: { name: 'announcements', version: '0.1.0' },

    onthisday: { name: 'onthisday', version: '0.2.0' },

    unpublished: { name: 'unpublished', version: '0.0.0' }
};

mUtil.setContentType = function(res, spec) {
    if (!spec.name || !spec.version) {
        throw new HTTPError({
            status: 500,
            type: 'invalid_content_type',
            title: 'Only use the allowed content-types',
            detail: `${spec.name}/${spec.version} is not an allowed content-type!`
        });
    }

    res.type(`application/json; charset=utf-8; profile="https://www.mediawiki.org/wiki/Specs/${spec.name}/${spec.version}"`);
};

/**
 * @returns true if val is null, undefined, an empty object, an empty array, or
 *          an empty string.
 */
mUtil.isEmpty = function(val) {
    return !underscore.isNumber(val)
        && !underscore.isBoolean(val)
        && underscore.isEmpty(val);
};

mUtil.isNonempty = underscore.negate(mUtil.isEmpty);

/**
 * @param [fallback]
 * @returns val if nonempty, else fallback.
*/
mUtil.defaultVal = function(val, fallback) {
    return underscore.isEmpty(val) ? fallback : val;
};

/**
 * @returns val less empty elements.
*/
mUtil.filterEmpty = function(val) {
    if (Array.isArray(val)) {
        return val.map(mUtil.filterEmpty).filter(mUtil.isNonempty);
    }
    if (underscore.isObject(val)) {
        return underscore.pick(underscore.mapObject(val, mUtil.filterEmpty), mUtil.isNonempty);
    }
    return val;
};

/**
 * Sets the ETag header on the response objecti, comprised of the revision ID and
 * the time UUID. If the latter is not given, the current time stamp is used to
 * generate it.
 *
 * @param {!Object}  response the HTTPResponse object on which to set the header
 * @param {?number} revision the revision integer ID to use
 * @param {?string}  tid      the time UUID to use; optional
 */
mUtil.setETag = function(response, revision, tid) {
    // we want to bail out if the revision hasn't been supplied, except
    // in the case revision === 0 because 0 is actually a valid rev_id
    if (!revision && revision !== 0) {
        return;
    }
    if (!tid) {
        tid = uuid.now().toString();
    }
    response.set('etag', `"${revision}/${tid}"`);
};

/**
 * Convert mobile to canonical domain,
 * e.g., 'en.m.wikipedia.org' => 'en.wikipedia.org'
 */
mUtil.mobileToCanonical = function(domain) {
    return domain.replace('.m.', '.');
};

/**
 * Remove the top-level domain from a domain string, e.g., 'en.wikipedia.org' ->
 * 'en.wikipedia'.
 */
mUtil.removeTLD = function(domain) {
    return domain.split('.').slice(0,2).join('.');
};

/**
 * Get the language of the wiki base don the domain name.
 * Example: 'en.wikipedia.org' -> 'en'.
 */
mUtil.getLanguageFromDomain = function(domain) {
    return domain.split('.')[0];
};

mUtil.isEnglishWikipedia = function(domain) {
    return (domain === 'en.wikipedia.org' || domain === 'en.wikipedia.beta.wmflabs.org');
};

mUtil.removeFragment = function(href) {
    if (href.indexOf('#') > -1) {
        return href.substring(0, href.indexOf('#'));
    }
    return href;
};

mUtil.removeLinkPrefix = function(href) {
    return href.replace(/^\.\//, '');
};

mUtil.extractDbTitleFromAnchor = function(anchor) {
    return anchor && mUtil.removeFragment(mUtil.removeLinkPrefix(anchor.getAttribute('href')));
};

// Merge two arrays of objects by the specified property.
// Stolen from https://jsfiddle.net/guya/eAWKR/.
mUtil.mergeByProp = function(arr1, arr2, prop, pushIfKeyNotFound) {
    if (!arr1 || !arr2) {
        return;
    }

    arr2.forEach((arr2obj) => {
        const arr1obj = arr1.find((arr1obj) => {
            return arr1obj[prop] === arr2obj[prop];
        });

        // If the object already exists, extend it with the new values from
        // arr2, otherwise conditionally add the new object to arr1.
        if (arr1obj) {
            Object.assign(arr1obj, arr2obj);
        } else if (pushIfKeyNotFound) {
            arr1.push(arr2obj);
        }
    });
};

/**
 * Takes an array of objects and makes the specified changes to the keys of each
 * member object.
 *
 * E.g., adjustMemberKeys(arr, ['to', 'from'], ['to', 'from'], ...)
 *
 * @param {!Array}  arr      an array of objects that will receive the change
 * pairs passed in as additional params
 */
mUtil.adjustMemberKeys = function(arr) {
    for (let i = 0, n = arr.length; i < n; i++) {
        for (let j = 1, m = arguments.length; j < m; j++) {
            if (arr[i][arguments[j][1]]) {
                arr[i][arguments[j][0]] = arr[i][arguments[j][1]];
                delete arr[i][arguments[j][1]];
            }
        }
    }
};

/**
 * Takes an array of objects and, for each object, creates the specified key (if
 * not already present) with the same value as the specified source key for each
 * change pair passed in as an additional parameter.
 *
 * E.g., fillInMemberKeys(arr, ['to', 'from'], ['to', 'from'], ...)
 *
 * @param {!Array}  arr      an array of objects that will receive the change
 * pairs passed in as additional params
 */
mUtil.fillInMemberKeys = function(arr) {
    for (let i = 0, n = arr.length; i < n; i++) {
        for (let j = 1, m = arguments.length; j < m; j++) {
            if (!arr[i][arguments[j][0]]) {
                arr[i][arguments[j][0]] = arr[i][arguments[j][1]];
            }
        }
    }
};

mUtil.getRbPageSummaryUrl = function(restbaseTpl, domain, title) {
    const request = restbaseTpl.expand({
        request: {
            params: {
                domain,
                path: `page/summary/${encodeURIComponent(title)}` },
        }
    });
    return request.uri;
};

mUtil.throw404 = function(message) {
    throw new HTTPError({
        status: 404,
        type: 'not_found',
        title: 'Not found',
        detail: message
    });
};

/* jslint bitwise: true */
/* eslint no-bitwise: ["error", { "allow": ["<<"] }] */
mUtil.hashCode = function(string) {
    return string.split('').reduce((prevHash, currVal) =>
       ((prevHash << 5) - prevHash) + currVal.charCodeAt(0), 0);
};

module.exports = mUtil;
<|endoftext|>


<commit_before>'use strict';

/**
 * File: mockRequest
 *
 * This file implements node.js's implementation of a 'request' object.
 * This is actually closer to what Express offers the user, in that the
 * body is really a parsed object of values.
 *
 * @author Howard Abrams <howard.abrams@gmail.com>
 */

/**
 * Function: createRequest
 *
 *    Creates a new mock 'request' instance. All values are reset to the
 *    defaults.
 *
 * Parameters:
 *
 *   options - An object of named parameters.
 *
 * Options:
 *
 *   method      - The method value, see <mockRequest._setMethod>
 *   url         - The url value, see <mockRequest._setURL>
 *   originalUrl - The originalUrl value, see <mockRequest._setOriginalUrl>
 *   params      - The parameters, see <mockRequest._setParam>
 *   body        - The body values, , see <mockRequest._setBody>
 */

var url = require('url');

function convertKeysToLowerCase(map) {
    var newMap = {};
    for(var key in map) {
        newMap[key.toLowerCase()] = map[key];
    }
    return newMap;
}

function createRequest(options) {

    if (!options) {
        options = {};
    }

    // creat mockRequest

    var mockRequest = {};

    mockRequest.method = (options.method) ? options.method : 'GET';
    mockRequest.url = (options.url) ? options.url : '';
    mockRequest.originalUrl = options.originalUrl || mockRequest.url;
    mockRequest.path = (options.url) ? url.parse(options.url).pathname : '';
    mockRequest.params = (options.params) ? options.params : {};
    if (options.session) {
        mockRequest.session = options.session;
    }
    mockRequest.cookies = (options.cookies) ? options.cookies : {};
    if (options.signedCookies) {
        mockRequest.signedCookies = options.signedCookies;
    }
    mockRequest.headers = (options.headers) ? convertKeysToLowerCase(options.headers) : {};
    mockRequest.body = (options.body) ? options.body : {};
    mockRequest.query = (options.query) ? options.query : {};
    mockRequest.files = (options.files) ? options.files : {};

    //parse query string from url to object
    if (Object.keys(mockRequest.query).length === 0) {
        mockRequest.query = require('querystring').parse(mockRequest.url.split('?')[1]);
    }

    /**
     * Return request header.
     *
     * The `Referrer` header field is special-cased,
     * both `Referrer` and `Referer` are interchangeable.
     *
     * Examples:
     *
     *     mockRequest.get('Content-Type');
     *     // => "text/plain"
     *
     *     mockRequest.get('content-type');
     *     // => "text/plain"
     *
     *     mockRequest.get('Something');
     *     // => undefined
     *
     * Aliased as `mockRequest.header()`.
     *
     * @param {String} name
     * @return {String}
     * @api public
     */

    mockRequest.get =
    mockRequest.header = function(name) {
        name = name.toLowerCase();
        switch (name) {
            case 'referer':
            case 'referrer':
                return mockRequest.headers.referrer || mockRequest.headers.referer;
            default:
                return mockRequest.headers[name];
        }
    };

    /**
     * Function: param
     *
     *   Return the value of param name when present.
     *   Lookup is performed in the following order:
     *   - req.params
     *   - req.body
     *   - req.query
     */
    mockRequest.param = function(parameterName) {
        if (mockRequest.params[parameterName]) {
            return mockRequest.params[parameterName];
        } else if (mockRequest.body[parameterName]) {
            return mockRequest.body[parameterName];
        } else if (mockRequest.query[parameterName]) {
            return mockRequest.query[parameterName];
        }
        return null;
    };

    /**
     * Function: _setParameter
     *
     *    Set parameters that the client can then get using the 'params'
     *    key.
     *
     * Parameters:
     *
     *   key - The key. For instance, 'bob' would be accessed: request.params.bob
     *   value - The value to return when accessed.
     */
    mockRequest._setParameter = function(key, value) {
        mockRequest.params[key] = value;
    };

    /**
     * Sets a variable that is stored in the session.
     *
     * @param variable The variable to store in the session
     * @param value    The value associated with the variable
     */
    mockRequest._setSessionVariable = function(variable, value) {
        if (typeof mockRequest.session !== 'object') {
            mockRequest.session = {};
        }
        mockRequest.session[variable] = value;
    };

    /**
     * Sets a variable that is stored in the cookies.
     *
     * @param variable The variable to store in the cookies
     * @param value    The value associated with the variable
     */
    mockRequest._setCookiesVariable = function(variable, value) {
        mockRequest.cookies[variable] = value;
    };

    /**
     * Sets a variable that is stored in the signed cookies.
     *
     * @param variable The variable to store in the signed cookies
     * @param value    The value associated with the variable
     */
    mockRequest._setSignedCookiesVariable = function(variable, value) {
        if (typeof mockRequest.signedCookies !== 'object') {
            mockRequest.signedCookies = {};
        }
        mockRequest.signedCookies[variable] = value;
    };

    /**
     * Sets a variable that is stored in the headers.
     *
     * @param variable The variable to store in the headers
     * @param value    The value associated with the variable
     */
    mockRequest._setHeadersVariable = function(variable, value) {
        variable = variable.toLowerCase();
        mockRequest.headers[variable] = value;
    };

    /**
     * Sets a variable that is stored in the files.
     *
     * @param variable The variable to store in the files
     * @param value    The value associated with the variable
     */
    mockRequest._setFilesVariable = function(variable, value) {
        mockRequest.files[variable] = value;
    };

    /**
     * Function: _setMethod
     *
     *    Sets the HTTP method that the client gets when the called the 'method'
     *    property. This defaults to 'GET' if it is not set.
     *
     * Parameters:
     *
     *   method - The HTTP method, e.g. GET, POST, PUT, DELETE, etc.
     *
     * Note: We don't validate the string. We just return it.
     */
    mockRequest._setMethod = function(method) {
        mockRequest.method = method;
    };

    /**
     * Function: _setURL
     *
     *    Sets the URL value that the client gets when the called the 'url'
     *    property.
     *
     * Parameters:
     *
     *   value - The request path, e.g. /my-route/452
     *
     * Note: We don't validate the string. We just return it. Typically, these
     * do not include hostname, port or that part of the URL.
     */
    mockRequest._setURL = function(value) {
        mockRequest.url = value;
    };

    /**
     * Function: _setOriginalUrl
     *
     *    Sets the URL value that the client gets when the called the 'originalUrl'
     *    property.
     *
     * Parameters:
     *
     *   value - The request path, e.g. /my-route/452
     *
     * Note: We don't validate the string. We just return it. Typically, these
     * do not include hostname, port or that part of the URL.
     */
    mockRequest._setOriginalUrl = function(value) {
        mockRequest.originalUrl = value;
    };

    /**
     * Function: _setBody
     *
     *    Sets the body that the client gets when the called the 'body'
     *    parameter. This defaults to 'GET' if it is not set.
     *
     * Parameters:
     *
     *   body - An object representing the body.
     *
     * If you expect the 'body' to come from a form, this typically means that
     * it would be a flat object of properties and values, as in:
     *
     * > {  name: 'Howard Abrams',
     * >    age: 522
     * > }
     *
     * If the client is expecting a JSON object through a REST interface, then
     * this object could be anything.
     */
    mockRequest._setBody = function(body) {
        mockRequest.body = body;
    };

    /**
     * Function: _addBody
     *
     *    Adds another body parameter the client gets when calling the 'body'
     *    parameter with another property value, e.g. the name of a form element
     *    that was passed in.
     *
     * Parameters:
     *
     *   key - The key. For instance, 'bob' would be accessed: request.params.bob
     *   value - The value to return when accessed.
     */
    mockRequest._addBody = function(key, value) {
        mockRequest.body[key] = value;
    };

    return mockRequest;

}

module.exports.createRequest = createRequest;
<commit_msg>Fixed issue 70<commit_after>'use strict';

/**
 * File: mockRequest
 *
 * This file implements node.js's implementation of a 'request' object.
 * This is actually closer to what Express offers the user, in that the
 * body is really a parsed object of values.
 *
 * @author Howard Abrams <howard.abrams@gmail.com>
 */

/**
 * Function: createRequest
 *
 *    Creates a new mock 'request' instance. All values are reset to the
 *    defaults.
 *
 * Parameters:
 *
 *   options - An object of named parameters.
 *
 * Options:
 *
 *   method      - The method value, see <mockRequest._setMethod>
 *   url         - The url value, see <mockRequest._setURL>
 *   originalUrl - The originalUrl value, see <mockRequest._setOriginalUrl>
 *   params      - The parameters, see <mockRequest._setParam>
 *   body        - The body values, , see <mockRequest._setBody>
 */

var url = require('url');

function convertKeysToLowerCase(map) {
    var newMap = {};
    for(var key in map) {
        newMap[key.toLowerCase()] = map[key];
    }
    return newMap;
}

function createRequest(options) {

    if (!options) {
        options = {};
    }

    // creat mockRequest

    var mockRequest = {};

    mockRequest.method = (options.method) ? options.method : 'GET';
    mockRequest.url = options.url || options.path || '';
    mockRequest.originalUrl = options.originalUrl || mockRequest.url;
    mockRequest.path = (options.url) ? url.parse(options.url).pathname : '';
    mockRequest.params = (options.params) ? options.params : {};
    if (options.session) {
        mockRequest.session = options.session;
    }
    mockRequest.cookies = (options.cookies) ? options.cookies : {};
    if (options.signedCookies) {
        mockRequest.signedCookies = options.signedCookies;
    }
    mockRequest.headers = (options.headers) ? convertKeysToLowerCase(options.headers) : {};
    mockRequest.body = (options.body) ? options.body : {};
    mockRequest.query = (options.query) ? options.query : {};
    mockRequest.files = (options.files) ? options.files : {};

    //parse query string from url to object
    if (Object.keys(mockRequest.query).length === 0) {
        mockRequest.query = require('querystring').parse(mockRequest.url.split('?')[1]);
    }

    /**
     * Return request header.
     *
     * The `Referrer` header field is special-cased,
     * both `Referrer` and `Referer` are interchangeable.
     *
     * Examples:
     *
     *     mockRequest.get('Content-Type');
     *     // => "text/plain"
     *
     *     mockRequest.get('content-type');
     *     // => "text/plain"
     *
     *     mockRequest.get('Something');
     *     // => undefined
     *
     * Aliased as `mockRequest.header()`.
     *
     * @param {String} name
     * @return {String}
     * @api public
     */

    mockRequest.get =
    mockRequest.header = function(name) {
        name = name.toLowerCase();
        switch (name) {
            case 'referer':
            case 'referrer':
                return mockRequest.headers.referrer || mockRequest.headers.referer;
            default:
                return mockRequest.headers[name];
        }
    };

    /**
     * Function: param
     *
     *   Return the value of param name when present.
     *   Lookup is performed in the following order:
     *   - req.params
     *   - req.body
     *   - req.query
     */
    mockRequest.param = function(parameterName) {
        if (mockRequest.params[parameterName]) {
            return mockRequest.params[parameterName];
        } else if (mockRequest.body[parameterName]) {
            return mockRequest.body[parameterName];
        } else if (mockRequest.query[parameterName]) {
            return mockRequest.query[parameterName];
        }
        return null;
    };

    /**
     * Function: _setParameter
     *
     *    Set parameters that the client can then get using the 'params'
     *    key.
     *
     * Parameters:
     *
     *   key - The key. For instance, 'bob' would be accessed: request.params.bob
     *   value - The value to return when accessed.
     */
    mockRequest._setParameter = function(key, value) {
        mockRequest.params[key] = value;
    };

    /**
     * Sets a variable that is stored in the session.
     *
     * @param variable The variable to store in the session
     * @param value    The value associated with the variable
     */
    mockRequest._setSessionVariable = function(variable, value) {
        if (typeof mockRequest.session !== 'object') {
            mockRequest.session = {};
        }
        mockRequest.session[variable] = value;
    };

    /**
     * Sets a variable that is stored in the cookies.
     *
     * @param variable The variable to store in the cookies
     * @param value    The value associated with the variable
     */
    mockRequest._setCookiesVariable = function(variable, value) {
        mockRequest.cookies[variable] = value;
    };

    /**
     * Sets a variable that is stored in the signed cookies.
     *
     * @param variable The variable to store in the signed cookies
     * @param value    The value associated with the variable
     */
    mockRequest._setSignedCookiesVariable = function(variable, value) {
        if (typeof mockRequest.signedCookies !== 'object') {
            mockRequest.signedCookies = {};
        }
        mockRequest.signedCookies[variable] = value;
    };

    /**
     * Sets a variable that is stored in the headers.
     *
     * @param variable The variable to store in the headers
     * @param value    The value associated with the variable
     */
    mockRequest._setHeadersVariable = function(variable, value) {
        variable = variable.toLowerCase();
        mockRequest.headers[variable] = value;
    };

    /**
     * Sets a variable that is stored in the files.
     *
     * @param variable The variable to store in the files
     * @param value    The value associated with the variable
     */
    mockRequest._setFilesVariable = function(variable, value) {
        mockRequest.files[variable] = value;
    };

    /**
     * Function: _setMethod
     *
     *    Sets the HTTP method that the client gets when the called the 'method'
     *    property. This defaults to 'GET' if it is not set.
     *
     * Parameters:
     *
     *   method - The HTTP method, e.g. GET, POST, PUT, DELETE, etc.
     *
     * Note: We don't validate the string. We just return it.
     */
    mockRequest._setMethod = function(method) {
        mockRequest.method = method;
    };

    /**
     * Function: _setURL
     *
     *    Sets the URL value that the client gets when the called the 'url'
     *    property.
     *
     * Parameters:
     *
     *   value - The request path, e.g. /my-route/452
     *
     * Note: We don't validate the string. We just return it. Typically, these
     * do not include hostname, port or that part of the URL.
     */
    mockRequest._setURL = function(value) {
        mockRequest.url = value;
    };

    /**
     * Function: _setOriginalUrl
     *
     *    Sets the URL value that the client gets when the called the 'originalUrl'
     *    property.
     *
     * Parameters:
     *
     *   value - The request path, e.g. /my-route/452
     *
     * Note: We don't validate the string. We just return it. Typically, these
     * do not include hostname, port or that part of the URL.
     */
    mockRequest._setOriginalUrl = function(value) {
        mockRequest.originalUrl = value;
    };

    /**
     * Function: _setBody
     *
     *    Sets the body that the client gets when the called the 'body'
     *    parameter. This defaults to 'GET' if it is not set.
     *
     * Parameters:
     *
     *   body - An object representing the body.
     *
     * If you expect the 'body' to come from a form, this typically means that
     * it would be a flat object of properties and values, as in:
     *
     * > {  name: 'Howard Abrams',
     * >    age: 522
     * > }
     *
     * If the client is expecting a JSON object through a REST interface, then
     * this object could be anything.
     */
    mockRequest._setBody = function(body) {
        mockRequest.body = body;
    };

    /**
     * Function: _addBody
     *
     *    Adds another body parameter the client gets when calling the 'body'
     *    parameter with another property value, e.g. the name of a form element
     *    that was passed in.
     *
     * Parameters:
     *
     *   key - The key. For instance, 'bob' would be accessed: request.params.bob
     *   value - The value to return when accessed.
     */
    mockRequest._addBody = function(key, value) {
        mockRequest.body[key] = value;
    };

    return mockRequest;

}

module.exports.createRequest = createRequest;
<|endoftext|>


<commit_before>/*
 * Patch for Model class to add validation and sanitizing methods.
 */

var async = require('async');

var modelPatch = module.exports = {

  validateAndSave: function(item, callback) {
    var self = this;
    this.validate(item, function(error, errors) {
      if (error) {
        // Aplication error.
        return callback(error);
      }
      if (errors.length > 0) {
        // Validation errors.
        callback(null, item, errors);
      }
      else {
        var typeSettings = self.type.settings;

        // Allow calling REST POST for validating non standalone types.
        if (typeSettings.standalone === false) {
          return callback(null, item);
        }

        self.save(self.filter(item), callback);
      }
    });
  },

  validate: function(item, callback) {
    var errors = [];
    var self = this;

    if (this.type.settings.polymorphic) {
      if (!item.type) {
        errors.push('Error: type is required.');
        return callback(null, errors);
      }
      else if (!(item.type in this.subtypes)) {
        errors.push('Error: unrecognized type: ' + item.type + '.');
        return callback(null, errors);
      }
      // Get field for polymorphic type subtypes.
      var fields = this.subtypes[item.type].type.settings.fields || {};
    }
    else {
      var fields = this.type.settings.fields || {};
    }

    // Validate type fields.
    async.each(Object.keys(fields), function(fieldName, next) {
      var fieldSettings = fields[fieldName];
      // Add field name to field settings to be used by the field validation
      // vallback to extract the field value from the item.
      // @todo in the long run we may want to add a typeField type to link the
      // type to its fields properly, so once type is loaded properly it will
      // have the name property set.
      fieldSettings.name = fieldName;

      // If field is required check if a value was supplied for it.
      if (fieldSettings.required && !(fieldName in item)) {
        errors.push(fieldSettings.title + ' is required.');
      }

      if (!(fieldName in item)) {
        // The field doesn't have a value, so nothing to validate.
        return next();
      }

      var Field = self.application.type('field');
      Field.load(fieldSettings.type, function(error, field) {
        if (error) {
          // Application error.
          return next(error);
        }
        if (!field || !field.validate) {
          // Field is of an unrecognized type or there's not a validate
          // callback.
          // @todo: log warning when type is not recognized.
          return next();
        }

        field.validate(fieldSettings, item, function(error, result) {
          if (error) {
            // Application error.
            return next(error);
          }

          if (result !== true && typeof result === 'string') {
            // Validation failed.
            errors = errors.concat(result);
          }

          next();
        });
      });

    }, function(error) {
      if (error) {
        // Application error.
        return callback(error);
      }
      callback(null, errors);
    });
  },

  filter: function(item, fields) {
    // Allow fieldless resources, if the resource type has no fields, return the
    // unmodified resource.
    if (!this.type.settings.fields) {
      return item;
    }

    fields = fields || Object.keys(this.type.settings.fields);

    var newResource = {};
    fields.forEach(function(field) {
      if (field in item) {
        newResource[field] = item[field];
      }
    });

    return newResource;
  }

};
<commit_msg>Improving model filter to work with polymorphic types.<commit_after>/*
 * Patch for Model class to add validation and sanitizing methods.
 */

var async = require('async');

var modelPatch = module.exports = {

  validateAndSave: function(item, callback) {
    var self = this;
    this.validate(item, function(error, errors) {
      if (error) {
        // Aplication error.
        return callback(error);
      }
      if (errors.length > 0) {
        // Validation errors.
        callback(null, item, errors);
      }
      else {
        var typeSettings = self.type.settings;

        // Allow calling REST POST for validating non standalone types.
        if (typeSettings.standalone === false) {
          return callback(null, item);
        }

        self.save(self.filter(item), callback);
      }
    });
  },

  validate: function(item, callback) {
    var errors = [];
    var self = this;

    if (this.type.settings.polymorphic) {
      if (!item.type) {
        errors.push('Error: type is required.');
        return callback(null, errors);
      }
      else if (!(item.type in this.subtypes)) {
        errors.push('Error: unrecognized type: ' + item.type + '.');
        return callback(null, errors);
      }
      // Get field for polymorphic type subtypes.
      var fields = this.subtypes[item.type].type.settings.fields || {};
    }
    else {
      var fields = this.type.settings.fields || {};
    }

    // Validate type fields.
    async.each(Object.keys(fields), function(fieldName, next) {
      var fieldSettings = fields[fieldName];
      // Add field name to field settings to be used by the field validation
      // vallback to extract the field value from the item.
      // @todo in the long run we may want to add a typeField type to link the
      // type to its fields properly, so once type is loaded properly it will
      // have the name property set.
      fieldSettings.name = fieldName;

      // If field is required check if a value was supplied for it.
      if (fieldSettings.required && !(fieldName in item)) {
        errors.push(fieldSettings.title + ' is required.');
      }

      if (!(fieldName in item)) {
        // The field doesn't have a value, so nothing to validate.
        return next();
      }

      var Field = self.application.type('field');
      Field.load(fieldSettings.type, function(error, field) {
        if (error) {
          // Application error.
          return next(error);
        }
        if (!field || !field.validate) {
          // Field is of an unrecognized type or there's not a validate
          // callback.
          // @todo: log warning when type is not recognized.
          return next();
        }

        field.validate(fieldSettings, item, function(error, result) {
          if (error) {
            // Application error.
            return next(error);
          }

          if (result !== true && typeof result === 'string') {
            // Validation failed.
            errors = errors.concat(result);
          }

          next();
        });
      });

    }, function(error) {
      if (error) {
        // Application error.
        return callback(error);
      }
      callback(null, errors);
    });
  },

  filter: function(item, fields) {
    var typeSettings = this.type.settings;

    // Allow fieldless resources, if the resource type has no fields, return the
    // unmodified resource.
    if (!typeSettings.polymorphic && !typeSettings.fields) {
      return item;
    }

    if (typeSettings.polymorphic) {
      var subTypeSettings = this.subtypes[item.type].type.settings;

      // Get fields from subtype settings if type is polymorphic.
      fields = fields || Object.keys(subTypeSettings.fields);

      // Add "type" field so it don't get removed.
      fields.unshift('type');
    }
    else {
      // Get field from type from type settings.
      fields = fields || Object.keys(typeSettings.fields);
    }

    var newResource = {};
    fields.forEach(function(field) {
      if (field in item) {
        newResource[field] = item[field];
      }
    });

    return newResource;
  }

};
<|endoftext|>


<commit_before>var _ = require("lodash");

module.exports = Chan;

Chan.Type = {
	CHANNEL: "channel",
	LOBBY: "lobby",
	QUERY: "query"
};

var id = 0;

function Chan(attr) {
	_.merge(this, _.extend({
		id: id++,
		type: Chan.Type.CHANNEL,
		name: "",
		messages: [],
		users: []
	}, attr));
}

Chan.prototype.sortUsers = function() {
	// ..
};
<commit_msg>Sort users<commit_after>var _ = require("lodash");

module.exports = Chan;

Chan.Type = {
	CHANNEL: "channel",
	LOBBY: "lobby",
	QUERY: "query"
};

var id = 0;

function Chan(attr) {
	_.merge(this, _.extend({
		id: id++,
		type: Chan.Type.CHANNEL,
		name: "",
		messages: [],
		users: []
	}, attr));
}

Chan.prototype.sortUsers = function() {
	this.users = _.sortBy(
		this.users,
		function(u) { return u.name.toLowerCase(); }
	);
	var modes = [
		"~",
		"%",
		"@",
		"+",
	].reverse();
	modes.forEach(function(mode) {
		this.users = _.remove(
			this.users,
			function(u) { return u.mode == mode; }
		).concat(this.users);
	}, this);
};
<|endoftext|>