<commit_before>$(document).ready(function() {
	function Task (element) {
		if (_.isUndefined(element)) {
			this.element = Task.create();
		} else {
			this.element = element;
		}
	}

	// TODO: state: moving, creating, none
	Task.prototype = {
		insertAfter: function(task) {
			if (this.element.parent().size() > 0) {
				var parent = this.parent();
				this.element.detach();
				parent.save();
			}
			var parent = task.parent();
			this.element.insertAfter(parent.element);
			parent.save();
		},

		insertChild: function(task) {
			if (this.element.parent().size() > 0) {
				var parent = this.parent();
				this.element.detach();
				parent.save();
			}
			this.element.appendTo(task.element.children(".task-list"));
			task.save();
		},

		remove: function() {
			function helper(x) {
				_.each(x.children(), helper);
				localStorage.removeItem(x.id());
			}

			var parent = this.parent();
			helper(this);
			parent.save();
		},

		children: function() {
			// TODO: make simpler
			return _.map(this.element.find("> .task-list > .task"), function(x) {
				return new Task($(x));
			});
		},

		parent: function() {
			return new Task(this.element.parents(".task").first());
		},

		// TODO: simpler attribute mechanism
		title: function(new_title) {
			if (_.isUndefined(new_title)) {
				return this.element.find("> div > .task-title").text();
			} else {
				this.element.find("> div > .task-title").text(new_title);
			}
		},

		id: function(new_id) {
			if (_.isUndefined(new_id)) {
				return this.element.attr("id");
			} else {
				this.element.attr("id", new_id);
			}
		},

		checked: function(new_checked) {
			if (_.isUndefined(new_checked)) {
				return this.element.find("> div > .checkbox-checked").size() == 1;
			} else {
				if (new_checked) {
					this.element.find("> div > .checkbox-unchecked")
						.removeClass("checkbox-unchecked")
						.addClass("checkbox-checked");
				} else {
					this.element.find("> div > .checkbox-checked")
						.removeClass("checkbox-checked")
						.addClass("checkbox-unchecked");
				}
			}
		},

		toggle: function() {
			var $checkbox_checked = this.element.find("> div > .checkbox-checked");
			var $checkbox_unchecked = this.element.find("> div > .checkbox-unchecked");

			$checkbox_unchecked
				.removeClass("checkbox-unchecked")
				.addClass("checkbox-checked");
			$checkbox_checked
				.removeClass("checkbox-checked")
				.addClass("checkbox-unchecked");
			this.save();
		},

		stringify: function() {
			return JSON.stringify({
				id: this.id(),
				title: this.title(),
				checked: this.checked(),
				children: _.map(this.children(), function(child) {
					return child.id();
				})
			});
		},

		isRoot: function() {
		},

		save: function() {
			localStorage.setItem(this.id(), this.stringify());
		}
	};

	Task.load = function(id) {
		var json = JSON.parse(localStorage.getItem(id));
		var task = Task.initialize(json);

		_.each(json.children, function(child) {
			Task.load(child).insertChild(task);
		});

		return task;
	}

	Task.initialize = function(o) {
		var task = new Task();

		// TODO: better mechanism for defaults?
		o.id = _.isUndefined(o.id) ? Task.createId() : o.id;
		o.title = _.isUndefined(o.title) ? "" : o.title;
		o.checked = _.isUndefined(o.checked) ? false : o.checked;

		task.id(o.id);
		task.title(o.title);
		task.checked(o.checked);
		task.save();

		return task;
	}

	Task.createId = function() {
		var id;
		if (localStorage.getItem("task-id") == null)
			id = 1;
		else
			id = 1 + parseInt(localStorage.getItem("task-id"));
		localStorage.setItem("task-id", id);
		return "task-" + id;
	}

	Task.get = function(selector) {
		// TODO: check to see if it's a string?
		return new Task(selector.closest(".task"));
	}

	Task.insertChildDrop = {
		hoverClass: "ui-state-highlight",
		drop : function(e, ui) {
			var $task = $(ui.draggable);
			$task.css({top:0,left:0});

			Task.get($task).insertChild(Task.get($(this)));
		}
	};

	Task.insertAfterDrop = {
		hoverClass: "ui-state-highlight",
		drop : function(e, ui) {
			var $task = $(ui.draggable);
			$task.css({top:0,left:0});

			Task.get($task).insertAfter(Task.get($(this)));
		}
	};

	Task.create = function(id) {
		id = _.isUndefined(id) ? id : createTaskId();

		var $task = $("#prototype > .task")
			.clone(deepWithDataAndEvents=true)
			.draggable({
				handle: "> *",
				revert: "invalid",
				revertDuration: 100,
			});

		$task.find(".task-insert-child")
			.droppable(Task.insertChildDrop);

		$task.find(".task-insert-after")
			.droppable(Task.insertAfterDrop);

		return $task;
	}

	// ******************************************************************

	$("#task-add").keypress(function(e) {
		if (e.keyCode == 13 && $("#task-add").val().trim() != "") {
			var task = Task.initialize({title: $("#task-add").val()})
				.insertChild(Task.get($("#task-root")));
			$("#task-add").val("");
		}
	});

	$(".checkbox-checked,.checkbox-unchecked").click(function(e) {
		Task.get($(e.currentTarget)).toggle();
	});

	$(".delete").click(function(e) {
		var task = Task.get($(e.currentTarget));
		task.remove();
	});

	$(".task-insert-child").click(function(e) {
		new Task().insertChild(Task.get($(e.currentTarget)));
	});

	$(".task-insert-after").click(function(e) {
		new Task().insertAfter(Task.get($(e.currentTarget)));
	});

	// TODO: make this work with drag/drop
	// we want this to be either on mouseup or as a drag/drop callback?
	// only have a single instance that moves around?
	// drag/drop needs just a little bit of snap
	$(".task-title").click(function(e) {
		var title = $(e.currentTarget);
		title.hide();
		title.siblings(".task-title-edit")
			.val(title.text())
			.show()
			.focus()
			.select();
	});

	$(".task-title-edit").focusout(function(e) {
		var $editing = $(e.currentTarget);
		var $title = $editing.siblings(".task-title");

		// TODO: keep the state of the item, if it's currently being created
		// destroy it if it's empty
		if ($editing.hasClass("task-title-moving"))
			return;
		if ($editing.val().trim() != "") {
			$title.text($editing.val());
			Task.get($title).save();
		}
		$editing.hide();
		$title.show();
	});

	var shiftDown = false;

	$(".task-title-edit").keydown(function(e) {
		switch (e.keyCode) {
		case 9:
			var $title = $(e.currentTarget);
			var task = Task.get($title);

			if (shiftDown) {
				var parent = task.parent();

				if (!parent.isRoot())
					return false;

				$title.addClass("task-title-moving");

				task.insertAfter(parent);
				parent.save();
				task.parent().save();

				$title.removeClass("task-title-moving");
				$title.focus().select();
			} else {
				var prev = task.prev();

				if (!prev.size())
					return false;

				$title.addClass("task-title-moving");

				task.insertAfter(prev.find("> div > .task-list"));
				prev.save();
				getParent(prev).save();

				$title.removeClass("task-title-moving");
				$title.focus().select();
			}
			return false;
		case 16:
			shiftDown = true;
			break;
		default:
		}
	});

	$(".task-title-edit").keyup(function(e) {
		switch (e.keyCode) {
		case 13:
			$(e.currentTarget).focusout();
			break;
		case 16:
			shiftDown = false;
			break;
		}
	});

	var root = JSON.parse(localStorage.getItem("task-root"));
	if (root != null) {
		var rootTask = Task.get($("#task-root"));
		_.each(root.children, function(child) {
			Task.load(child).insertChild(rootTask);
		});
	}
});

<commit_msg>Added in special create state<commit_after>$(document).ready(function() {
	function Task (element) {
		if (_.isUndefined(element)) {
			this.element = Task.create();
		} else {
			this.element = element;
		}
	}

	// TODO: state: moving, creating, none
	Task.prototype = {
		insertAfter: function(task) {
			if (this.element.parent().size() > 0) {
				var parent = this.parent();
				this.element.detach();
				parent.save();
			}
			this.element.insertAfter(task.element);
			task.parent().save();
		},

		insertChild: function(task) {
			if (this.element.parent().size() > 0) {
				var parent = this.parent();
				this.element.detach();
				parent.save();
			}
			this.element.appendTo(task.element.children(".task-list"));
			task.save();
		},

		remove: function() {
			function helper(task) {
				_.each(task.children(), helper);
				localStorage.removeItem(task.id());
				task.element.remove();
			}

			var parent = this.parent();
			helper(this);
			parent.save();
		},

		previous: function() {
			return new Task(this.element.prev(".task"));
		},

		children: function() {
			// TODO: make simpler
			return _.map(this.element.find("> .task-list > .task"), function(x) {
				return new Task($(x));
			});
		},

		parent: function() {
			return new Task(this.element.parents(".task").first());
		},

		// TODO: simpler attribute mechanism
		title: function(new_title) {
			if (_.isUndefined(new_title)) {
				return this.element.find("> div > .task-title").text();
			} else {
				this.element.find("> div > .task-title").text(new_title);
			}
		},

		id: function(new_id) {
			if (_.isUndefined(new_id)) {
				return this.element.attr("id");
			} else {
				this.element.attr("id", new_id);
			}
		},

		checked: function(new_checked) {
			if (_.isUndefined(new_checked)) {
				return this.element.find("> div > .checkbox-checked").size() == 1;
			} else {
				if (new_checked) {
					this.element.find("> div > .checkbox-unchecked")
						.removeClass("checkbox-unchecked")
						.addClass("checkbox-checked");
				} else {
					this.element.find("> div > .checkbox-checked")
						.removeClass("checkbox-checked")
						.addClass("checkbox-unchecked");
				}
			}
		},

		toggle: function() {
			var $checkbox_checked = this.element.find("> div > .checkbox-checked");
			var $checkbox_unchecked = this.element.find("> div > .checkbox-unchecked");

			$checkbox_unchecked
				.removeClass("checkbox-unchecked")
				.addClass("checkbox-checked");
			$checkbox_checked
				.removeClass("checkbox-checked")
				.addClass("checkbox-unchecked");
			this.save();
		},

		stringify: function() {
			return JSON.stringify({
				id: this.id(),
				title: this.title(),
				checked: this.checked(),
				children: _.map(this.children(), function(child) {
					return child.id();
				})
			});
		},

		exists: function() {
			return this.element.size() == 1;
		},

		save: function() {
			localStorage.setItem(this.id(), this.stringify());
		}
	};

	Task.load = function(id) {
		var json = JSON.parse(localStorage.getItem(id));
		var task = Task.initialize(json);

		_.each(json.children, function(child) {
			Task.load(child).insertChild(task);
		});

		return task;
	}

	Task.initialize = function(o) {
		var task = new Task();

		// TODO: better mechanism for defaults?
		o.id = _.isUndefined(o.id) ? Task.createId() : o.id;
		o.title = _.isUndefined(o.title) ? "" : o.title;
		o.checked = _.isUndefined(o.checked) ? false : o.checked;

		task.id(o.id);
		task.title(o.title);
		task.checked(o.checked);
		task.save();

		return task;
	}

	Task.createId = function() {
		var id;
		if (localStorage.getItem("task-id") == null)
			id = 1;
		else
			id = 1 + parseInt(localStorage.getItem("task-id"));
		localStorage.setItem("task-id", id);
		return "task-" + id;
	}

	Task.get = function(selector) {
		// TODO: check to see if it's a string?
		return new Task(selector.closest(".task"));
	}

	Task.insertChildDrop = {
		hoverClass: "ui-state-highlight",
		drop : function(e, ui) {
			var $task = $(ui.draggable);
			$task.css({top:0,left:0});

			Task.get($task).insertChild(Task.get($(this)));
		}
	};

	Task.insertAfterDrop = {
		hoverClass: "ui-state-highlight",
		drop : function(e, ui) {
			var $task = $(ui.draggable);
			$task.css({top:0,left:0});

			Task.get($task).insertAfter(Task.get($(this)));
		}
	};

	Task.create = function(id) {
		id = _.isUndefined(id) ? id : createTaskId();

		var $task = $("#prototype > .task")
			.clone(deepWithDataAndEvents=true)
			.draggable({
				handle: "> *",
				revert: "invalid",
				revertDuration: 100,
			});

		$task.find(".task-insert-child")
			.droppable(Task.insertChildDrop);

		$task.find(".task-insert-after")
			.droppable(Task.insertAfterDrop);

		return $task;
	}

	// ******************************************************************

	$("#task-add").keypress(function(e) {
		if (e.keyCode == 13 && $("#task-add").val().trim() != "") {
			var task = Task.initialize({title: $("#task-add").val()})
				.insertChild(new Task($("#task-root")));
			$("#task-add").val("");
		}
	});

	$(".checkbox-checked,.checkbox-unchecked").click(function(e) {
		Task.get($(e.currentTarget)).toggle();
	});

	$(".delete").click(function(e) {
		var task = Task.get($(e.currentTarget));
		task.remove();
	});

	$(".task-insert-child").click(function(e) {
		var task = Task.initialize({});
		task.insertChild(Task.get($(e.currentTarget)));
		task.element.find("> div > .task-title").click();
		task.element.find("> div > .task-title-edit").addClass("task-title-create");
	});

	$(".task-insert-after").click(function(e) {
		var task = Task.initialize({});
		task.insertAfter(Task.get($(e.currentTarget)));
		task.element.find("> div > .task-title").click();
		task.element.find("> div > .task-title-edit").addClass("task-title-create");
	});

	// TODO: make this work with drag/drop
	// we want this to be either on mouseup or as a drag/drop callback?
	// only have a single instance that moves around?
	// drag/drop needs just a little bit of snap
	$(".task-title").click(function(e) {
		var title = $(e.currentTarget);
		title.hide();
		title.siblings(".task-title-edit")
			.val(title.text())
			.show()
			.focus()
			.select();
	});

	$(".task-title-edit").focusout(function(e) {
		var $editing = $(e.currentTarget);
		var $title = $editing.siblings(".task-title");

		// TODO: keep the state of the item, if it's currently being created
		// destroy it if it's empty
		if ($editing.hasClass("task-title-moving"))
			return;
		if ($editing.val().trim() != "") {
			// TODO use the API
			$title.text($editing.val());
			Task.get($title).save();
			$editing.removeClass("task-title-create");
		} else if ($editing.hasClass("task-title-create")) {
			Task.get($title).remove();
			return;
		}
		$editing.hide();
		$title.show();
	});

	var shiftDown = false;

	$(".task-title-edit").keydown(function(e) {
		switch (e.keyCode) {
		case 9:
			var $title = $(e.currentTarget);
			var task = Task.get($title);

			if (shiftDown) {
				var parent = task.parent();

				if (parent.id() == "task-root")
					return false;

				$title.addClass("task-title-moving");
				task.insertAfter(parent);
				$title.removeClass("task-title-moving");

				$title.focus().select();
			} else {
				var previous = task.previous();

				if (!previous.exists())
					return false;

				$title.addClass("task-title-moving");
				task.insertChild(previous);
				$title.removeClass("task-title-moving");

				$title.focus().select();
			}
			return false;
		case 16:
			shiftDown = true;
			break;
		default:
		}
	});

	$(".task-title-edit").keyup(function(e) {
		switch (e.keyCode) {
		case 13:
			$(e.currentTarget).focusout();
			break;
		case 16:
			shiftDown = false;
			break;
		}
	});

	var root = JSON.parse(localStorage.getItem("task-root"));
	if (root != null) {
		var rootTask = new Task($("#task-root"));
		_.each(root.children, function(child) {
			Task.load(child).insertChild(rootTask);
		});
	}
});

<|endoftext|>


<commit_before>var much = (function () {

	/**
	 * Provides requestAnimationFrame in a cross browser way.
	 * @author greggman / http://greggman.com/
	 */

	if (!window.requestAnimationFrame) {
		window.requestAnimationFrame = (function() {
			return window.webkitRequestAnimationFrame ||
				window.mozRequestAnimationFrame ||
				window.oRequestAnimationFrame ||
				window.msRequestAnimationFrame ||
				function(callback, element) {
					window.setTimeout(callback, 1000 / 60 );
				};
			})
		();
	}

	/**
 	* @author Hans Eklund, North Kingdom
 	*
 	* Modified and packaged into a module by Andrus Asumets.
 	*/

 	var toomuch = {};
	var elements = [];
	var elementId;
	var element = {}
	var index = 0;
	var animationFrame;
	var prefixedTransform;

    var settings = {
    	element: null,
        currentScale: 0.5,
        currentRotation: 0,
        containerWidth: 600,
        containerHeight: 400,
        minScale: 0.5,
        maxScale: 1.5,
        restrict: false,
        easing: 0,
        boundaries: {
            left: 0,
            right: 0,
            top: 0,
            bottom: 0
        },
        dragStartX: 0,
        dragStartY: 0,
        dragX: 0,
        dragY: 0,
        dragdDX: 0,
        dragdDY: 0,
        dragging: false,
        touchStartDistance: 0,
        touchStartAngle: 0,
        posX: 0,
        posY: 0,
        velocityX: 0,
        velocityY: 0,
        clientX: 0,
        clientY: 0
    }

	toomuch.add = function (options) {
		if('transform' in document.body.style) {
			prefixedTransform = 'transform';
		} else if('webkitTransform' in document.body.style) {
			prefixedTransform = 'webkitTransform';
		}

		var elementSettings = merge_options(settings, options);

		elementSettings.elementId = options.element.id;
		elements.push(elementSettings);
		elementId = options.element.id;

		var elementHTML = document.getElementById(elementId);
		if(window.PointerEvent) {
			element.pointers = [];

			elementHTML.addEventListener('pointerdown', pointerDownHandler, false);
		} else {
			elementHTML.addEventListener('touchstart', onTouchStart);
		}

		setElement(elementId);
		startAnimationFrame();

		return elementSettings;
	}

	toomuch.stop = function() {
		stop();
	}

	toomuch.remove = function(element) {
		for (i = 0; i < elements.length; i++) {
			if (elements[i].element.id == element.id) {
				var j = 0;

				elements.splice(i, 1);

				j = i - 1;
				if (j < 0) { j = 0 };
				index = j;

				break;
			}
		}

		stop();
	}

	function stop() {
		stopAnimationFrame();
		elements = [];
		elementId = null;
		element = {};
		index = 0;
	}

	function merge_options(obj1,obj2) {
	    var obj3 = {};

	    for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
	    for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }

	    return obj3;
	}

	function setElement(id) {
		for (i = 0; i < elements.length; i++) {
			if (elements[i].elementId === id) {
				index = i;
				element = elements[index];

				break;
			}
		}
	}

	function onTouchStart(event) {
		elementId = this.id;
		setElement(elementId);

		if(event.touches.length === 1) {
			if(!element.dragging) {
				document.addEventListener('touchmove', onTouchMove);
				document.addEventListener('touchend', onTouchEnd);
				document.addEventListener('touchcancel', onTouchEnd);

				handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
			}
		} else if(event.touches.length === 2) {
			handleGestureStart(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY);
		}

		startAnimationFrame();
	}

	function onTouchMove(event) {
		event.preventDefault();

		if(event.touches.length === 1) {
			handleDragging(event.touches[0].clientX, event.touches[0].clientY);
		} else if(event.touches.length === 2) {
			handleGesture(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY);
		}
	}

	function onTouchEnd(event) {
		if(event.touches.length === 0 && element.dragging) {
			element.dragging = false;

			document.removeEventListener('touchmove', onTouchMove);
			document.removeEventListener('touchend', onTouchEnd);
			document.removeEventListener('touchcancel', onTouchEnd);
		} else if(event.touches.length === 1) {
			handleGestureStop();
			handleDragStart(event.touches[0].clientX, event.touches[0].clientY);
		}

		return true;
	}

	function indexOfPointer(pointerId){
		for (var i = 0; i < element.pointers.length; i++) {
			if(element.pointers[i].pointerId === pointerId) {
		   		return i;
			}
		}
		return -1;
	}

	function pointerDownHandler(event) {
		elementId = this.id;
		setElement(elementId);

		var pointerIndex = indexOfPointer(event.pointerId);

		if(pointerIndex < 0) {
			element.pointers.push(event);
		} else {
			element.pointers[pointerIndex] = event;
		}
		if(input.pointers.length === 1) {
			handleDragStart(element.pointers[0].clientX , element.pointers[0].clientY);

			window.addEventListener('pointermove', pointerMoveHandler, false);
			window.addEventListener('pointerup', pointerUpHandler, false);
		} else if(input.pointers.length === 2) {
			handleGestureStart(element.pointers[0].clientX, element.pointers[0].clientY, element.pointers[1].clientX, element.pointers[1].clientY);
		}
	}

	function pointerMoveHandler(event) {
		var pointerIndex = indexOfPointer(event.pointerId);

		if(pointerIndex < 0) {
			input.pointers.push(event);
		} else {
			input.pointers[pointerIndex] = event;
		}

		if(input.pointers.length === 1) {
			handleDragging(element.pointers[0].clientX, element.pointers[0].clientY);
		} else if(input.pointers.length === 2 ) {
			handleGesture(element.pointers[0].clientX, element.pointers[0].clientY, element.pointers[1].clientX, element.pointers[1].clientY);
		}
	}

	function pointerUpHandler(event) {
		element.pointers = [];

		window.removeEventListener('pointermove', pointerMoveHandler, false);
		window.removeEventListener('pointerup', pointerUpHandler, false);

		handleDragStop();
		handleGestureStop();
	}

	function handleDragStart(x, y) {
		element.dragging = true;
		element.dragX = x;
		element.dragY = y;
	}

	function handleDragging(x, y) {
		if(element.dragging) {
			element.dragdDX += x - element.dragX;
			element.dragdDY += y - element.dragY;

			element.dragX = x;
			element.dragY = y;
		}
	}

	function handleGestureStart(x1, y1, x2, y2) {
		element.isGesture = true;

		//calculate distance and angle between fingers
		var dx = x2 - x1;
		var dy = y2 - y1;

		element.touchStartDistance = Math.sqrt(dx * dx + dy * dy);
		element.touchStartAngle = Math.atan2(dy, dx);

		//we also store the current scale and rotation of the actual object we are affecting. This is needed because to enable incremental rotation/scaling.
		element.startScale = element.currentScale;
		element.startAngle = element.currentRotation;
	}

	function handleGesture(x1, y1, x2, y2) {
		if(element.isGesture) {

			//calculate distance and angle between fingers
			var dx = x2 - x1;
			var dy = y2 - y1;
			var touchDistance = Math.sqrt(dx * dx + dy * dy);
			var touchAngle = Math.atan2(dy, dx);

			//calculate the difference between current touch values and the start values
			var scalePixelChange = touchDistance - element.touchStartDistance;
			var angleChange = touchAngle - element.touchStartAngle;

			//calculate how much this should affect the actual object
			element.currentScale = element.startScale + scalePixelChange * 0.01;
			element.currentRotation = element.startAngle + (angleChange * 180 / Math.PI);

			if(element.currentScale < element.minScale) element.currentScale = element.minScale;
			if(element.currentScale > element.maxScale) element.currentScale = element.maxScale;
		}
	}

	function handleGestureStop() {
		element.isGesture = false;
	}

	function onAnimationFrame() {
		animationFrame = requestAnimationFrame(onAnimationFrame);

		if(elements.length === 0) { return };

		var elementHTML = document.getElementById(elementId);
		element = element

		if(element.dragdDX !== 0) element.velocityX = element.dragdDX;
		if(element.dragdDY !== 0) element.velocityY = element.dragdDY;

		element.posX += element.velocityX;
		element.posY += element.velocityY;

		if(element.restrict) {
			//restict horizontally
			if(element.posX < element.boundaries.left) element.posX = element.boundaries.left;
			else if(element.posX > element.boundaries.right) element.posX = element.boundaries.right;

			//restict vertically
			if(element.posY < element.boundaries.top) element.posY = element.boundaries.top;
			else if(element.posY > element.boundaries.bottom) element.posY = element.boundaries.bottom;
		}

		//set the transform
		elementHTML.style[prefixedTransform] = 'translate(' + element.posX + 'px,' + element.posY + 'px) rotate(' + element.currentRotation + 'deg) scale(' + element.currentScale + ') translateZ(0)';

		element.velocityX = element.velocityX * element.easing;
		element.velocityY = element.velocityY * element.easing;

		element.dragdDX = 0;
		element.dragdDY = 0;

		if (typeof element.callback == 'function') {
			element.callback.call(null, element);
		}

		elements[index] = element;
	}

	function startAnimationFrame() {
	    if (!animationFrame) {
			onAnimationFrame();
	    }
	}

	function stopAnimationFrame() {
	    if (animationFrame) {
			window.cancelAnimationFrame(animationFrame);
			animationFrame = undefined;
	    }
	}

	return toomuch;
}());<commit_msg>Fix remove()<commit_after>var much = (function () {

	/**
	 * Provides requestAnimationFrame in a cross browser way.
	 * @author greggman / http://greggman.com/
	 */

	if (!window.requestAnimationFrame) {
		window.requestAnimationFrame = (function() {
			return window.webkitRequestAnimationFrame ||
				window.mozRequestAnimationFrame ||
				window.oRequestAnimationFrame ||
				window.msRequestAnimationFrame ||
				function(callback, element) {
					window.setTimeout(callback, 1000 / 60 );
				};
			})
		();
	}

	/**
 	* @author Hans Eklund, North Kingdom
 	*
 	* Modified and packaged into a module by Andrus Asumets.
 	*/

 	var toomuch = {};
	var elements = [];
	var elementId;
	var element = {}
	var index = 0;
	var animationFrame;
	var prefixedTransform;

    var settings = {
    	element: null,
        currentScale: 0.5,
        currentRotation: 0,
        containerWidth: 600,
        containerHeight: 400,
        minScale: 0.5,
        maxScale: 1.5,
        restrict: false,
        easing: 0,
        boundaries: {
            left: 0,
            right: 0,
            top: 0,
            bottom: 0
        },
        dragStartX: 0,
        dragStartY: 0,
        dragX: 0,
        dragY: 0,
        dragdDX: 0,
        dragdDY: 0,
        dragging: false,
        touchStartDistance: 0,
        touchStartAngle: 0,
        posX: 0,
        posY: 0,
        velocityX: 0,
        velocityY: 0,
        clientX: 0,
        clientY: 0
    }

	toomuch.add = function (options) {
		if('transform' in document.body.style) {
			prefixedTransform = 'transform';
		} else if('webkitTransform' in document.body.style) {
			prefixedTransform = 'webkitTransform';
		}

		var elementSettings = merge_options(settings, options);

		elementSettings.elementId = options.element.id;
		elements.push(elementSettings);
		elementId = options.element.id;

		var elementHTML = document.getElementById(elementId);
		if(window.PointerEvent) {
			element.pointers = [];

			elementHTML.addEventListener('pointerdown', pointerDownHandler, false);
		} else {
			elementHTML.addEventListener('touchstart', onTouchStart);
		}

		setElement(elementId);
		startAnimationFrame();

		return elementSettings;
	}

	toomuch.stop = function() {
		stopAnimationFrame();
		elements = [];
		elementId = null;
		element = {};
		index = 0;
	}

	toomuch.remove = function(element) {
		for (i = 0; i < elements.length; i++) {
			if (elements[i].element.id == element.id) {
				var j = 0;

				elements.splice(i, 1);

				j = i - 1;
				if (j < 0) { j = 0 };
				index = j;

				break;
			}
		}

		if (elements.length > 0) {
			elementId = elements[index].element.id;
			setElement(elementId);
		}
		else {
			stopAnimationFrame();
		}
	}

	function merge_options(obj1,obj2) {
	    var obj3 = {};

	    for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
	    for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }

	    return obj3;
	}

	function setElement(id) {
		for (i = 0; i < elements.length; i++) {
			if (elements[i].elementId === id) {
				index = i;
				element = elements[index];

				break;
			}
		}
	}

	function onTouchStart(event) {
		elementId = this.id;
		setElement(elementId);

		if(event.touches.length === 1) {
			if(!element.dragging) {
				document.addEventListener('touchmove', onTouchMove);
				document.addEventListener('touchend', onTouchEnd);
				document.addEventListener('touchcancel', onTouchEnd);

				handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
			}
		} else if(event.touches.length === 2) {
			handleGestureStart(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY);
		}

		startAnimationFrame();
	}

	function onTouchMove(event) {
		event.preventDefault();

		if(event.touches.length === 1) {
			handleDragging(event.touches[0].clientX, event.touches[0].clientY);
		} else if(event.touches.length === 2) {
			handleGesture(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY);
		}
	}

	function onTouchEnd(event) {
		if(event.touches.length === 0 && element.dragging) {
			element.dragging = false;

			document.removeEventListener('touchmove', onTouchMove);
			document.removeEventListener('touchend', onTouchEnd);
			document.removeEventListener('touchcancel', onTouchEnd);
		} else if(event.touches.length === 1) {
			handleGestureStop();
			handleDragStart(event.touches[0].clientX, event.touches[0].clientY);
		}

		return true;
	}

	function indexOfPointer(pointerId){
		for (var i = 0; i < element.pointers.length; i++) {
			if(element.pointers[i].pointerId === pointerId) {
		   		return i;
			}
		}
		return -1;
	}

	function pointerDownHandler(event) {
		elementId = this.id;
		setElement(elementId);

		var pointerIndex = indexOfPointer(event.pointerId);

		if(pointerIndex < 0) {
			element.pointers.push(event);
		} else {
			element.pointers[pointerIndex] = event;
		}
		if(input.pointers.length === 1) {
			handleDragStart(element.pointers[0].clientX , element.pointers[0].clientY);

			window.addEventListener('pointermove', pointerMoveHandler, false);
			window.addEventListener('pointerup', pointerUpHandler, false);
		} else if(input.pointers.length === 2) {
			handleGestureStart(element.pointers[0].clientX, element.pointers[0].clientY, element.pointers[1].clientX, element.pointers[1].clientY);
		}
	}

	function pointerMoveHandler(event) {
		var pointerIndex = indexOfPointer(event.pointerId);

		if(pointerIndex < 0) {
			input.pointers.push(event);
		} else {
			input.pointers[pointerIndex] = event;
		}

		if(input.pointers.length === 1) {
			handleDragging(element.pointers[0].clientX, element.pointers[0].clientY);
		} else if(input.pointers.length === 2 ) {
			handleGesture(element.pointers[0].clientX, element.pointers[0].clientY, element.pointers[1].clientX, element.pointers[1].clientY);
		}
	}

	function pointerUpHandler(event) {
		element.pointers = [];

		window.removeEventListener('pointermove', pointerMoveHandler, false);
		window.removeEventListener('pointerup', pointerUpHandler, false);

		handleDragStop();
		handleGestureStop();
	}

	function handleDragStart(x, y) {
		element.dragging = true;
		element.dragX = x;
		element.dragY = y;
	}

	function handleDragging(x, y) {
		if(element.dragging) {
			element.dragdDX += x - element.dragX;
			element.dragdDY += y - element.dragY;

			element.dragX = x;
			element.dragY = y;
		}
	}

	function handleGestureStart(x1, y1, x2, y2) {
		element.isGesture = true;

		//calculate distance and angle between fingers
		var dx = x2 - x1;
		var dy = y2 - y1;

		element.touchStartDistance = Math.sqrt(dx * dx + dy * dy);
		element.touchStartAngle = Math.atan2(dy, dx);

		//we also store the current scale and rotation of the actual object we are affecting. This is needed because to enable incremental rotation/scaling.
		element.startScale = element.currentScale;
		element.startAngle = element.currentRotation;
	}

	function handleGesture(x1, y1, x2, y2) {
		if(element.isGesture) {

			//calculate distance and angle between fingers
			var dx = x2 - x1;
			var dy = y2 - y1;
			var touchDistance = Math.sqrt(dx * dx + dy * dy);
			var touchAngle = Math.atan2(dy, dx);

			//calculate the difference between current touch values and the start values
			var scalePixelChange = touchDistance - element.touchStartDistance;
			var angleChange = touchAngle - element.touchStartAngle;

			//calculate how much this should affect the actual object
			element.currentScale = element.startScale + scalePixelChange * 0.01;
			element.currentRotation = element.startAngle + (angleChange * 180 / Math.PI);

			if(element.currentScale < element.minScale) element.currentScale = element.minScale;
			if(element.currentScale > element.maxScale) element.currentScale = element.maxScale;
		}
	}

	function handleGestureStop() {
		element.isGesture = false;
	}

	function onAnimationFrame() {
		animationFrame = requestAnimationFrame(onAnimationFrame);

		if(elements.length === 0) { return };

		var elementHTML = document.getElementById(elementId);
		element = element

		if(element.dragdDX !== 0) element.velocityX = element.dragdDX;
		if(element.dragdDY !== 0) element.velocityY = element.dragdDY;

		element.posX += element.velocityX;
		element.posY += element.velocityY;

		if(element.restrict) {
			//restict horizontally
			if(element.posX < element.boundaries.left) element.posX = element.boundaries.left;
			else if(element.posX > element.boundaries.right) element.posX = element.boundaries.right;

			//restict vertically
			if(element.posY < element.boundaries.top) element.posY = element.boundaries.top;
			else if(element.posY > element.boundaries.bottom) element.posY = element.boundaries.bottom;
		}

		//set the transform
		elementHTML.style[prefixedTransform] = 'translate(' + element.posX + 'px,' + element.posY + 'px) rotate(' + element.currentRotation + 'deg) scale(' + element.currentScale + ')';

		element.velocityX = element.velocityX * element.easing;
		element.velocityY = element.velocityY * element.easing;

		element.dragdDX = 0;
		element.dragdDY = 0;

		if (typeof element.callback == 'function') {
			element.callback.call(null, element);
		}

		elements[index] = element;
	}

	function startAnimationFrame() {
	    if (!animationFrame) {
			onAnimationFrame();
	    }
	}

	function stopAnimationFrame() {
	    if (animationFrame) {
			window.cancelAnimationFrame(animationFrame);
			animationFrame = undefined;
	    }
	}

	return toomuch;
}());
<|endoftext|>


<commit_before>define([], function () {
    "use strict";

    var api = {
        step: 30,
        dispersion: 30,
        debugPoints: true,
        showTime: true,
        minSpread: 1,
        maxSpread: 20
    }

    var currentElement = null;
    var keys = {
        up: 38,
        down: 40,
        left: 37,
        right: 39,
        enter: 13,
        esc: 17
    }

    function debugPoint(point) {
        if (api.debugPoints) {
            var debugElement = document.createElement('div');
            debugElement.className = 'debug-point';
            debugElement.style.top = point.y + "px";
            debugElement.style.left = point.x + "px";
            document.body.appendChild(debugElement);
        }
    }

    function clearDebugPoints() {
        var points = document.querySelectorAll('.debug-point');

        for(var i=0; i<points.length; i++) {
            points[i].remove();
        }
    }

    function defaultIsNavigable(element) {
        return element.classList.contains('navigable');
    }

    function getStartingPoint(element, direction) {
        var rect = element.getBoundingClientRect();
        var x;
        var y;

        switch(direction.x) {
            case -1:
                x = rect.left;
                break;

            case 0:
                x = rect.left + rect.width/2;
                break;

            case 1:
                x = rect.right;
                break;
        }

        switch(direction.y) {
            case -1:
                y = rect.top;
                break;

            case 0:
                y = rect.top + rect.height/2;
                break;

            case 1:
                y = rect.bottom;
                break;
        }

        return {
            x: x,
            y: y
        }
    }

    function findNextNavigable(params) {

        var el;
        var elements = [];
        var errorCount = 0;
        var point;
        var offset;
        var spread = params.spread;
        var direction = params.direction;

        for(var i=0; i<spread; i++) {
            el = null;
            offset = (i * api.dispersion) - (spread * api.dispersion * 0.5);

            point = {
                x: params.x + Math.abs(direction.y) * offset,
                y: params.y + Math.abs(direction.x) * offset
            }
            debugPoint(point);

            try {
                el = findNavigableFromPoint(point);

                if (elements.indexOf(el) === -1) {
                    elements.push(el);
                }

            } catch (e) {
                errorCount++;
            }
        }

        if (errorCount === spread) {
            throw new Error('out of bounds');
        }

        return elements[0];
    }

    function findNavigableFromPoint(point) {
        var element = document.elementFromPoint(point.x, point.y);

        if (element === null) {
            throw new Error('out of bounds');
        }

        while (true) {
            if (element === document.body || element === document.body.parentElement) {
                element = null;
                break;
            }

            if (api.isNavigable(element)) {
                break;
            }

            element = element.parentElement;
        }

        return element;
    }

    function blur(element) {
        element.classList.remove('focused');
    }

    function focus(element) {
        element.classList.add('focused');
    }

    function navigate(direction) {
        var i=0;
        var el;
        var start = getStartingPoint(currentElement, direction);
        var spread = 0;
        var minSpread = ~~currentElement.getAttribute('nav-min-spread') || api.minSpread;
        var maxSpread = ~~currentElement.getAttribute('nav-max-spread') || api.maxSpread;

        clearDebugPoints();

        while(true) {
            i++;
            spread++;

            if (spread < minSpread) {
                spread = minSpread;
            }

            if (spread > maxSpread) {
                spread = maxSpread;
            }

            try {
                el = findNextNavigable({
                    x: start.x + direction.x * api.step * i,
                    y: start.y + direction.y * api.step * i,
                    spread: spread,
                    direction: direction
                });

                if (el && el !== currentElement) {
                    api.blur(currentElement);
                    currentElement = el;
                    api.focus(currentElement);
                    break;
                }

            } catch (e) {
                console.log('Not found element');
                break;
            }

            if (i > 1000) {
                console.error("Something went wrong, infinite loop!");
                break;
            }

        }
    }

    function keyHandler(event) {
        if (api.showTime) {
            console.time('navi');
        }

        switch(event.keyCode) {

            case keys.up:
                navigate({x: 0, y: -1});
                break;

            case keys.down:
                navigate({x: 0, y: 1});
                break;

            case keys.left:
                navigate({x: -1, y: 0});
                break;

            case keys.right:
                navigate({x: 1, y: 0});
                break;
        }

        if (api.showTime) {
            console.timeEnd('navi');
        }
    }

    function init() {
        console.log('init');
        currentElement = document.querySelector(".focused");
    }

    api.keyHandler = keyHandler;
    api.init = init;
    api.isNavigable = defaultIsNavigable;
    api.focus = focus;
    api.blur = blur;

    return api;
});

<commit_msg>Added custom event, removed console.time<commit_after>define([], function () {
    "use strict";

    var api = {
        step: 30,
        dispersion: 30,
        debugPoints: true,
        minSpread: 1,
        maxSpread: 20
    }

    var currentElement = null;
    var keys = {
        up: 38,
        down: 40,
        left: 37,
        right: 39,
        enter: 13,
        esc: 17
    };

    function debugPoint(point) {
        if (api.debugPoints) {
            var debugElement = document.createElement('div');
            debugElement.className = 'debug-point';
            debugElement.style.top = point.y + "px";
            debugElement.style.left = point.x + "px";
            document.body.appendChild(debugElement);
        }
    }

    function clearDebugPoints() {
        var points = document.querySelectorAll('.debug-point');

        for(var i=0; i<points.length; i++) {
            points[i].remove();
        }
    }

    function defaultIsNavigable(element) {
        return element.classList.contains('navigable');
    }

    function getStartingPoint(element, direction) {
        var rect = element.getBoundingClientRect();
        var x;
        var y;

        switch(direction.x) {
            case -1:
                x = rect.left;
                break;

            case 0:
                x = rect.left + rect.width/2;
                break;

            case 1:
                x = rect.right;
                break;
        }

        switch(direction.y) {
            case -1:
                y = rect.top;
                break;

            case 0:
                y = rect.top + rect.height/2;
                break;

            case 1:
                y = rect.bottom;
                break;
        }

        return {
            x: x,
            y: y
        }
    }

    function findNextNavigable(params) {

        var el;
        var elements = [];
        var errorCount = 0;
        var point;
        var offset;
        var spread = params.spread;
        var direction = params.direction;

        for(var i=0; i<spread; i++) {
            el = null;
            offset = (i * api.dispersion) - (spread * api.dispersion * 0.5);

            point = {
                x: params.x + Math.abs(direction.y) * offset,
                y: params.y + Math.abs(direction.x) * offset
            }
            debugPoint(point);

            try {
                el = findNavigableFromPoint(point);

                if (elements.indexOf(el) === -1) {
                    elements.push(el);
                }

            } catch (e) {
                errorCount++;
            }
        }

        if (errorCount === spread) {
            throw new Error('out of bounds');
        }

        return elements[0];
    }

    function findNavigableFromPoint(point) {
        var element = document.elementFromPoint(point.x, point.y);

        if (element === null) {
            throw new Error('out of bounds');
        }

        while (true) {
            if (element === document.body || element === document.body.parentElement) {
                element = null;
                break;
            }

            if (api.isNavigable(element)) {
                break;
            }

            element = element.parentElement;
        }

        return element;
    }

    function blur(element) {
        element.classList.remove('focused');
    }

    function focus(element) {
        element.classList.add('focused');
    }

    function navigate(direction) {
        var i=0;
        var el;
        var start = getStartingPoint(currentElement, direction);
        var spread = 0;
        var minSpread = ~~currentElement.getAttribute('nav-min-spread') || api.minSpread;
        var maxSpread = ~~currentElement.getAttribute('nav-max-spread') || api.maxSpread;

        clearDebugPoints();

        while(true) {
            i++;
            spread++;

            if (spread < minSpread) {
                spread = minSpread;
            }

            if (spread > maxSpread) {
                spread = maxSpread;
            }

            try {
                el = findNextNavigable({
                    x: start.x + direction.x * api.step * i,
                    y: start.y + direction.y * api.step * i,
                    spread: spread,
                    direction: direction
                });

                if (el && el !== currentElement) {
                    api.blur(currentElement);
                    currentElement = el;
                    api.focus(currentElement);
                    break;
                }

            } catch (e) {
                console.log('Not found element');
                break;
            }

            if (i > 1000) {
                console.error("Something went wrong, infinite loop!");
                break;
            }

        }
    }

    function createNaviEvent(keyEvent) {
        var event = new CustomEvent('navigate', {
            bubble: true,
            cancelable: true
        });
        event.keyCode = keyEvent.keyCode

        return event;
    }

    function defaultNavigation(event) {
        switch(event.keyCode) {

            case keys.up:
                navigate({x: 0, y: -1});
                break;

            case keys.down:
                navigate({x: 0, y: 1});
                break;

            case keys.left:
                navigate({x: -1, y: 0});
                break;

            case keys.right:
                navigate({x: 1, y: 0});
                break;
        }
    }

    function keyHandler(keyboardEvent) {
        var event;

        event = createNaviEvent(keyboardEvent);
        currentElement.dispatchEvent(event);

        if (event.defaultPrevented === false) {
            defaultNavigation(event);
        }
    }

    function init() {
        console.log('init');
        currentElement = document.querySelector(".focused");
    }

    api.keyHandler = keyHandler;
    api.init = init;
    api.isNavigable = defaultIsNavigable;
    api.focus = focus;
    api.blur = blur;

    return api;
});

<|endoftext|>


<commit_before>var packager = require('electron-packager');
var pkg = require('./package.json');

var options = {
	dir       : './',
	out       : './dist',
	overwrite : true,
	asar      : true,
//	platform  : 'darwin,win32,linux',
//	arch      : 'x64,ia32',
	version   : '0.33.8', // version of Electron

	prune     : true,
	ignore    : 'node_module|tests|dist|pack\.js|Gruntfile\.js|ignore|\.DS_Store|\.jshintrc|\.settings',

	name            : pkg.productName,
	'app-version'   : pkg.version,
//	icon            : ''  // not created
	'app-bundle-id' : 'jp.pzv.puzzlevan',
//	'version-string':{ // for Windows env.
//		FileDescription: pkg.description,
//		FileVersion    : pkg.version,
//		ProductVersion : pkg.version,
//		ProductName    : pkg.name,
//		InternalName   : pkg.name
//	}
};
function done(error, appPath){
	if(error){ throw new Error(error);}
	var appPathLower = appPath[0].replace(pkg.productName, pkg.name);
	var dirname = appPathLower.split(/\//g).pop();
	if(appPath[0].match('win32')){
		require('fs').renameSync(appPath[0], appPathLower);
		require('fs').renameSync(appPath[0]+'/'+pkg.productName+'.exe', appPathLower+'/'+pkg.name+'.exe');
	}
	else if(appPath[0].match('linux')){
		require('fs').renameSync(appPath[0], appPathLower);
		require('fs').renameSync(appPath[0]+'/'+pkg.productName, appPathLower+'/'+pkg.name);
	}
	else{ /* darwin */
		require('fs').renameSync(appPath[0]+'/', appPathLower+'/');
	}

	console.log('Building package done! --> '+appPathLower);

	if(process.argv.indexOf('--zip')>=2){
		require('child_process').exec('zip -9r -y ../'+dirname+'.zip *', {cwd:appPathLower}, function(err, stdout, stderr){
			console.log('Archiving package done! --> '+dirname+'.zip');
		});
	}
}

require('child_process').exec('rm -r dist/*');
[['darwin','x64'],['linux','ia32'],['linux','x64'],['win32','ia32']].forEach(function(item){
	options.platform = item[0];
	options.arch     = item[1];
	packager(options, done);
});
<commit_msg>package: Add version number to zip file name<commit_after>var packager = require('electron-packager');
var pkg = require('./package.json');

var options = {
	dir       : './',
	out       : './dist',
	overwrite : true,
	asar      : true,
//	platform  : 'darwin,win32,linux',
//	arch      : 'x64,ia32',
	version   : '0.33.8', // version of Electron

	prune     : true,
	ignore    : 'node_module|tests|dist|pack\.js|Gruntfile\.js|ignore|\.DS_Store|\.jshintrc|\.settings',

	name            : pkg.productName,
	'app-version'   : pkg.version,
//	icon            : ''  // not created
	'app-bundle-id' : 'jp.pzv.puzzlevan',
//	'version-string':{ // for Windows env.
//		FileDescription: pkg.description,
//		FileVersion    : pkg.version,
//		ProductVersion : pkg.version,
//		ProductName    : pkg.name,
//		InternalName   : pkg.name
//	}
};
function done(error, appPath){
	if(error){ throw new Error(error);}
	var appPathLower = appPath[0].replace(pkg.productName, pkg.name);
	var dirname = appPathLower.split(/\//g).pop();
	if(appPath[0].match('win32')){
		require('fs').renameSync(appPath[0], appPathLower);
		require('fs').renameSync(appPath[0]+'/'+pkg.productName+'.exe', appPathLower+'/'+pkg.name+'.exe');
	}
	else if(appPath[0].match('linux')){
		require('fs').renameSync(appPath[0], appPathLower);
		require('fs').renameSync(appPath[0]+'/'+pkg.productName, appPathLower+'/'+pkg.name);
	}
	else{ /* darwin */
		require('fs').renameSync(appPath[0]+'/', appPathLower+'/');
	}

	console.log('Building package done! --> '+appPathLower);

	if(process.argv.indexOf('--zip')>=2){
		var zipfilename = dirname.replace(/puzzlevan/,'puzzlevan-v'+pkg.version)+'.zip';
		require('child_process').exec('zip -9r -y ../'+zipfilename+' *', {cwd:appPathLower}, function(err, stdout, stderr){
			console.log('Archiving package done! --> '+zipfilename);
		});
	}
}

require('child_process').exec('rm -r dist/*');
[['darwin','x64'],['linux','ia32'],['linux','x64'],['win32','ia32']].forEach(function(item){
	options.platform = item[0];
	options.arch     = item[1];
	packager(options, done);
});
<|endoftext|>


<commit_before>console.log("start of page.js");
$(document).ready(function(){
  console.log("document is ready.");
  $("#search").click(function(){
    // $("#container").html($("#trackNumber").text());
    console.log("search clicked");
    $("#container").html("查询的快递号：" + $("#trackNumber").val());
    $("#search").click(function(e){
      e.preventDefault();
      $.ajax({
        type:"GET",
        async:true,
        url:"http://www.kuaidi100.com/query?type=shunfeng",
        data:{postid:$("#trackNumber").val()},
        success:function(data) {
          // DO SOMETHING
              console.log(data);
            }
      });
    });
  });
});
<commit_msg>Add test data<commit_after>console.log("start of page.js");
$(document).ready(function(){
  console.log("document is ready.");
  $("#search").click(function(){
    // $("#container").html($("#trackNumber").text());
    //for test, we can use type = shunfeng and postid = 608582127345
    console.log("search clicked");
    $("#container").html("查询的快递号：" + $("#trackNumber").val());
    $("#search").click(function(e){
      e.preventDefault();
      $.ajax({
        type:"GET",
        async:true,
        url:"http://www.kuaidi100.com/query?type=shunfeng",
        data:{postid:$("#trackNumber").val()},
        success:function(data) {
          // DO SOMETHING
              console.log(data);
            }
      });
    });
  });
});
<|endoftext|>


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

var myconfig = {features: false}
if (process.env["http_proxy"]) {
    myconfig.http_proxy = process.env.http_proxy
}

function getopt(args) {
    var set = {}

    function is_option(str) {
        if (str.length === 2 && str[0] === '-') {
            return true
        } else {
            return false
        }
    }

    (function filter_option(index) {
        var arg
        for (; index < args.length; index++) {
            arg = args[index]
            if (is_option(arg)) {
                if (index + 1 < args.length && !is_option(args[index+1])) {
                   set[arg] = args[++index]
                } else {
                   set[arg] = null
                }
            }
        }
    })(0)

    return set
}

function print_index(index) {
    console.log("title:\t", index.title)
    console.log("author:\t", index.author)
    console.log("cover:\t", index.cover)
    console.log("==== Table of Contecnts ====")
    index.toc.forEach(function (item) {
        console.log(item.name, " => ", item.url)
    })
}

function read_index(url, further_operation) {
    require("jsdom").env(
        url,
        myconfig,
        function (errors, window) {
            function extractNovelInfo(parentNode) {
                var rc = {}
                var pat = /^ (.+):(.+)$/
                for (var c = parentNode.firstChild; c !== null; c = c.nextSibling) {
                    if (c.nodeType === window.Node.TEXT_NODE) {
                        var tmp = pat.exec(c.data)
                        if (tmp !== null) {
                            var key = tmp[1]
                            var value = tmp[2]
                            switch (key) {
                                case "作者":
                                    rc.author = value; break;
                                case "状态":
                                    rc.status = value; break;
                                case "简介":
                                    rc.brief = value; break;
                            }
                        }
                    }
                }
                return rc
            }

            function get_toc(toc) {
                var rc = []
                var list = toc.getElementsByClassName("zl")
                for (var i = 0; i < list.length; i++) {
                    var li = list[i]
                    var a = li.firstChild
                    var text = a.firstChild.data
                    var link = a.href
                    rc.push({name: text, url: link})
                }
                return rc
            }

            var document = window.document
            var tit = document.getElementsByClassName("tit")[0]
            var header = extractNovelInfo(tit.parentNode)
            var index = {
                "title": tit.firstChild.firstChild.data,
                "cover": tit.nextSibling.src,
                "author": header.author,
                "toc": get_toc(document.getElementsByClassName("tit")[1]
                    .parentNode.children[1])
            }
            window.close();
            further_operation(index)
       })
}

function save_chapter(html, destdir, filename) {
    var fs = require("fs")
    if (destdir[destdir.length - 1] !== '/') {
        destdir = destdir + '/'
    }
    fs.writeFileSync(destdir + filename, html)
}

function fetch_chapter(args) {
    var item = args.item
    var dest = args.dest
    var chain_func = args.chain_func
    require("jsdom").env(
        item.url,
        myconfig,
        function (errors, window) {
            function removeNode(node) {
                node.parentNode.removeChild(node)
            }
            function removeNodes(nodes) {
                var to_delete = []
                for (var i = 0; i < nodes.length; i++) {
                    to_delete.push(nodes[i])
                }
                for (var i = 0; i < to_delete.length; i++) {
                    removeNode(to_delete[i])
                }
            }

            var document = window.document
            var content = document.getElementById("content")
            removeNodes(content.getElementsByTagName("script"))
            removeNodes(content.getElementsByClassName("bad"))
            removeNode(content.lastChild)
            removeNode(content.lastChild)
            removeNode(content.lastChild)
            removeNode(content.lastChild)

            var html = [
        '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"',
        '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
        '',
        '',
        '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">',
        '<title>',
        item.name,
        '</title>',
        '',
        '',
        content.innerHTML,
        ''].join("")
            if (!dest) {
                console.log(html)
            } else {
                (function() {
                    var filename
                    var url = decodeURI(item.url)
                    var buffer = []

                    if (url[url.length-1] == '/') {
                        url = url.slice(0, url.length - 1)
                    }
                    for (var i = url.length - 1; i >= 0; i--) {
                        if (url[i] !== '/') {
                            buffer.push(url[i])
                        } else {
                            break
                        }
                    }
                    chain_func(html, buffer.reverse().join(""), args)
                })();
            }
        })
}

function download_index(index, dir, start) {
    var count = -1
    var toc = index.toc
    var length = toc.length

    if (start) {
        count +=  (start - 1)
    }

    var generator = function() {
       return toc[++count]
    }
    var args = {
        "generator": generator,
        "dest": dir,
    }

    function chain_func(html, filename, args) {
        save_chapter(html, args.dest, filename)
        args.item = generator()
        if (args.item) {
           console.log("fetch ", count+1, '/', length, " : ", args.item.name)
           fetch_chapter(args)
        }
    }
    args.chain_func = chain_func
    args.item = generator()
    console.log("fetch ", count+1, '/', length, " : ", args.item.name)
    fetch_chapter(args)
}

(function main() {
   var options = getopt(process.argv)
   if (options["-l"]) { // list toc and header info
       read_index(options["-l"], print_index)
   } else if (options["-d"]) { // download chapters
       if (options["-o"]) {
            (function (dir) {
                var fs = require("fs")
                var stat = fs.statSync(dir)
                var begin = 1
                if (options["-c"]) {
                    begin = parseInt(options["-c"], 10)
                }
                if (stat.isDirectory()) {
                    read_index(options["-d"], (function (index) {
                        download_index(index, dir, begin)
                    }))
                } else {
                    console.error(dir, "is not a directory")
                }
            })(options["-o"])
       } else {
            console.error("the output directory must be specified by -o")
       }
   } else if (options["-f"]) { // fetch and print chapter
       fetch_chapter({"item": {"url" : options["-f"], "name": "test page"}})
   } else if (options["-F"]) { // download chapter
       fetch_chapter({"item":{"url": options["-F"], "name": "test page"}},
               ".",
               save_chapter)
   } else {
       console.error("wrong arguments")
   }
})()
<commit_msg>automatically detect and use the 'http_proxt` env var<commit_after>#!/usr/bin/env node

var myconfig = {features: false}
if (process.env["http_proxy"]) {
    myconfig.http_proxy = process.env.http_proxy
}

function http_request(url, callback) {

    function parse_dom(input) {
        require("jsdom").env(input, myconfig, callback)
    }

    var http_proxy = process.env["http_proxy"]
    if (http_proxy) {
        (function () {
            require('request')(
                {
                    url: url,
                    proxy: http_proxy,
                },
                function(error, response, html) {
                    if (!error && response.statusCode == 200) {
                        parse_dom(html)
                    }
                })
         })()
    } else {
        parse_dom(url)
    }
}

function getopt(args) {
    var set = {}

    function is_option(str) {
        if (str.length === 2 && str[0] === '-') {
            return true
        } else {
            return false
        }
    }

    (function filter_option(index) {
        var arg
        for (; index < args.length; index++) {
            arg = args[index]
            if (is_option(arg)) {
                if (index + 1 < args.length && !is_option(args[index+1])) {
                   set[arg] = args[++index]
                } else {
                   set[arg] = null
                }
            }
        }
    })(0)

    return set
}

function print_index(index) {
    console.log("title:\t", index.title)
    console.log("author:\t", index.author)
    console.log("cover:\t", index.cover)
    console.log("==== Table of Contecnts ====")
    index.toc.forEach(function (item) {
        console.log(item.name, " => ", item.url)
    })
}

function read_index(url, further_operation) {
    http_request(url,
        function (errors, window) {
            function extractNovelInfo(parentNode) {
                var rc = {}
                var pat = /^ (.+):(.+)$/
                for (var c = parentNode.firstChild; c !== null; c = c.nextSibling) {
                    if (c.nodeType === window.Node.TEXT_NODE) {
                        var tmp = pat.exec(c.data)
                        if (tmp !== null) {
                            var key = tmp[1]
                            var value = tmp[2]
                            switch (key) {
                                case "作者":
                                    rc.author = value; break;
                                case "状态":
                                    rc.status = value; break;
                                case "简介":
                                    rc.brief = value; break;
                            }
                        }
                    }
                }
                return rc
            }

            function get_toc(toc) {
                var rc = []
                var list = toc.getElementsByClassName("zl")
                for (var i = 0; i < list.length; i++) {
                    var li = list[i]
                    var a = li.firstChild
                    var text = a.firstChild.data
                    var link = a.href
                    rc.push({name: text, url: link})
                }
                return rc
            }

            var document = window.document
            var tit = document.getElementsByClassName("tit")[0]
            var header = extractNovelInfo(tit.parentNode)
            var index = {
                "title": tit.firstChild.firstChild.data,
                "cover": tit.nextSibling.src,
                "author": header.author,
                "toc": get_toc(document.getElementsByClassName("tit")[1]
                    .parentNode.children[1])
            }
            window.close();
            further_operation(index)
       })
}

function save_chapter(html, destdir, filename) {
    var fs = require("fs")
    if (destdir[destdir.length - 1] !== '/') {
        destdir = destdir + '/'
    }
    fs.writeFileSync(destdir + filename, html)
}

function fetch_chapter(args) {
    var item = args.item
    var dest = args.dest
    var chain_func = args.chain_func
    http_request(
        item.url,
        function (errors, window) {
            function removeNode(node) {
                node.parentNode.removeChild(node)
            }
            function removeNodes(nodes) {
                var to_delete = []
                for (var i = 0; i < nodes.length; i++) {
                    to_delete.push(nodes[i])
                }
                for (var i = 0; i < to_delete.length; i++) {
                    removeNode(to_delete[i])
                }
            }

            var document = window.document
            var content = document.getElementById("content")
            removeNodes(content.getElementsByTagName("script"))
            removeNodes(content.getElementsByClassName("bad"))
            removeNode(content.lastChild)
            removeNode(content.lastChild)
            removeNode(content.lastChild)
            removeNode(content.lastChild)

            var html = [
        '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"',
        '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
        '',
        '',
        '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">',
        '<title>',
        item.name,
        '</title>',
        '',
        '',
        content.innerHTML,
        ''].join("")
            if (!dest) {
                console.log(html)
            } else {
                (function() {
                    var filename
                    var url = decodeURI(item.url)
                    var buffer = []

                    if (url[url.length-1] == '/') {
                        url = url.slice(0, url.length - 1)
                    }
                    for (var i = url.length - 1; i >= 0; i--) {
                        if (url[i] !== '/') {
                            buffer.push(url[i])
                        } else {
                            break
                        }
                    }
                    chain_func(html, buffer.reverse().join(""), args)
                })();
            }
        })
}

function download_index(index, dir, start) {
    var count = -1
    var toc = index.toc
    var length = toc.length

    if (start) {
        count +=  (start - 1)
    }

    var generator = function() {
       return toc[++count]
    }
    var args = {
        "generator": generator,
        "dest": dir,
    }

    function chain_func(html, filename, args) {
        save_chapter(html, args.dest, filename)
        args.item = generator()
        if (args.item) {
           console.log("fetch ", count+1, '/', length, " : ", args.item.name)
           fetch_chapter(args)
        }
    }
    args.chain_func = chain_func
    args.item = generator()
    console.log("fetch ", count+1, '/', length, " : ", args.item.name)
    fetch_chapter(args)
}

(function main() {
   var options = getopt(process.argv)
   if (options["-l"]) { // list toc and header info
       read_index(options["-l"], print_index)
   } else if (options["-d"]) { // download chapters
       if (options["-o"]) {
            (function (dir) {
                var fs = require("fs")
                var stat = fs.statSync(dir)
                var begin = 1
                if (options["-c"]) {
                    begin = parseInt(options["-c"], 10)
                }
                if (stat.isDirectory()) {
                    read_index(options["-d"], (function (index) {
                        download_index(index, dir, begin)
                    }))
                } else {
                    console.error(dir, "is not a directory")
                }
            })(options["-o"])
       } else {
            console.error("the output directory must be specified by -o")
       }
   } else if (options["-f"]) { // fetch and print chapter
       fetch_chapter({"item": {"url" : options["-f"], "name": "test page"}})
   } else if (options["-F"]) { // download chapter
       fetch_chapter({"item":{"url": options["-F"], "name": "test page"}},
               ".",
               save_chapter)
   } else {
       console.error("wrong arguments")
   }
})()
<|endoftext|>


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

//var isWindows = process.platform === 'win32';
//var util = require('util');

var SEP = require("./codec");
//var PATH_SEP = SEP.PATH_SEP

function objectToString(o) {
  return Object.prototype.toString.call(o);
}

var isArray = Array.isArray;

function isBoolean(arg) {
  return typeof arg === 'boolean';
}

function isNullOrUndefined(arg) {
  return arg == null;
}
function isString(arg) {
  return typeof arg === 'string';
}

function isNumber(arg) {
  return typeof arg === 'number';
}

function isUndefined(arg) {
  return arg === void 0;
}

function isObject(arg) {
  return typeof arg === 'object' && arg !== null;
}

function isFunction(arg) {
  return typeof arg === 'function';
}

function isDate(d) {
  return isObject(d) && objectToString(d) === '[object Date]';
}
// resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
// if parts[0] is "." means relative path and allowAboveRoot.
function normalizeArray(parts, allowAboveRoot) {
  // if the path tries to go above the root, `up` ends up > 0
  var up = 0;
  if (isNullOrUndefined(allowAboveRoot)) {
      switch (parts[0]) {
        case '.':
            allowAboveRoot = true;
            break;
        case SEP.PATH_SEP:
            allowAboveRoot =false;
            parts.splice(0,1);
            break;
      }
  }
  for (var i = parts.length - 1; i >= 0; i--) {
    var last = parts[i];
    if (last === '.') {
      parts.splice(i, 1);
    } else if (last === '..') {
      parts.splice(i, 1);
      up++;
    } else if (up) {
      parts.splice(i, 1);
      up--;
    }
  }

  // if the path is allowed to go above the root, restore leading ..s
  if (allowAboveRoot) {
    for (; up--; up) {
      parts.unshift('..');
    }
  }

  return parts;
}

exports.normalizeArray = normalizeArray;

/* posix */

  // Split a filename into [root, dir, basename, ext], unix version
  // 'root' is just a slash, or nothing.
  //var splitPathRe =
  //    /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
  var splitPathRe = new RegExp("^("+SEP.PATH_SEP+"?|)([\\s\\S]*?)((?:\\.{1,2}|[^"+SEP.PATH_SEP+"]+?|)(\.[^."+SEP.PATH_SEP+"]*|))(?:["+SEP.PATH_SEP+"]*)$");
  var splitPath = function(filename) {
    return splitPathRe.exec(filename).slice(1);
  };

  // path.resolve([from ...], to)
  // posix version
  // return [resolvedAbsolute, parts...]
  // the arguments can be string or array
  resolveArray = exports.resolveArray = function() {
    var resolvedPath = [],
        resolvedAbsolute = false;

    for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
      var path = (i >= 0) ? arguments[i] : ".";

      // Skip empty and invalid entries
      if (isArray(path)) {
          if (path.length === 0) {
            //treat empty array as root path
            resolvedAbsolute = true;
          } else {
            resolvedPath = path.filter(Boolean).concat(resolvedPath);
            resolvedAbsolute = path[0] === "" || path[0] !== '.'
          }
          continue;
      } else if (!isString(path)) {
        throw new TypeError('Arguments to path.resolve must be strings');
      } else if (!path) {
        continue;
      }

      resolvedPath = path.split(SEP.PATH_SEP).filter(Boolean).concat(resolvedPath);
      //resolvedPath = path + '/' + resolvedPath;
      resolvedAbsolute = path.charAt(0) === SEP.PATH_SEP;
    }

    // At this point the path should be resolved to a full absolute path, but
    // handle relative paths to be safe (might happen when process.cwd() fails)

    // Normalize the path
    //resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) {
    //  return !!p;
    //}), !resolvedAbsolute).join('/');
    resolvedPath = normalizeArray(resolvedPath, !resolvedAbsolute);
    resolvedPath.unshift(resolvedAbsolute);
    return resolvedPath;
  };

  exports.resolve = function() {
    var resolvedPath = resolveArray.apply(null,arguments);
    var resolvedAbsolute = resolvedPath[0];
    resolvedPath.shift(0,1);
    return ((resolvedAbsolute ? SEP.PATH_SEP : '') + resolvedPath.join(SEP.PATH_SEP)) || '.';
  };

  // path.normalize(path)
  // posix version
  exports.normalize = function(path) {
    var isAbsolute = exports.isAbsolute(path),
        trailingSlash = path[path.length - 1] === SEP.PATH_SEP,
        segments = path.split(SEP.PATH_SEP),
        nonEmptySegments = [];

    // Normalize the path
    for (var i = 0; i < segments.length; i++) {
      if (segments[i]) {
        nonEmptySegments.push(segments[i]);
      }
    }
    path = normalizeArray(nonEmptySegments, !isAbsolute).join(SEP.PATH_SEP);

    if (!path && !isAbsolute) {
      path = '.';
    }
    if (path && trailingSlash) {
      path += SEP.PATH_SEP;
    }

    return (isAbsolute ? SEP.PATH_SEP : '') + path;
  };

  // posix version
  exports.isAbsolute = function(path) {
    return path.charAt(0) === SEP.PATH_SEP;
  };

  // path.join can mixture array and string arguments now!
  // path.join("path1", ["path2", "path3"], "path4")
  // = path1/path2/path3/path4
  exports.join = function() {
    var path = '';
    var vPathSep = SEP.PATH_SEP;
    for (var i = 0; i < arguments.length; i++) {
      var segment = arguments[i];
      // Skip empty and invalid entries
      if (isArray(segment)) {
          if (segment.length === 0 && path.length === 0) {
              path = vPathSep
          } else {
            segment = segment.filter(Boolean).join(vPathSep);
            if (segment) {
              path += vPathSep + segment;
            }
          }
          continue;
      } else if (!isString(segment)) {
        throw new TypeError('Arguments to path.resolve must be strings');
      } else if (!segment) {
        continue;
      }

      if (!isString(segment)) {
        throw new TypeError('Arguments to path.join must be strings');
      }
      if (segment) {
        if (!path) {
          path += segment;
        } else {
          path += vPathSep + segment;
        }
      }
    }
    return exports.normalize(path);
  };

  // path.relative(from, to)
  // posix version
  exports.relative = function(from, to) {
    var vPathSep = SEP.PATH_SEP;
    var fromParts = resolveArray(from);
    var toParts = resolveArray(to);
    fromParts.shift(0,1);
    toParts.shift(0,1);

    /*
    function trim(arr) {
      var start = 0;
      for (; start < arr.length; start++) {
        if (arr[start] !== '') break;
      }

      var end = arr.length - 1;
      for (; end >= 0; end--) {
        if (arr[end] !== '') break;
      }

      if (start > end) return [];
      return arr.slice(start, end + 1);
    }

    var fromParts = trim(from.split(vPathSep));
    var toParts = trim(to.split(vPathSep));
    */

    var length = Math.min(fromParts.length, toParts.length);
    var samePartsLength = length;
    var i;
    for (i = 0; i < length; i++) {
      if (fromParts[i] !== toParts[i]) {
        samePartsLength = i;
        break;
      }
    }

    var outputParts = [];
    for (i = samePartsLength; i < fromParts.length; i++) {
      outputParts.push('..');
    }

    outputParts = outputParts.concat(toParts.slice(samePartsLength));

    return outputParts.join(vPathSep);
  };

  exports.sep = SEP.PATH_SEP;
  exports.delimiter = ':';

exports.dirname = function(path) {
  var result = splitPath(path),
      root = result[0],
      dir = result[1];

  if (!root && !dir) {
    // No dirname whatsoever
    return '.';
  }

  if (dir) {
    // It has a dirname, strip trailing slash
    dir = dir.substr(0, dir.length - 1);
  }

  return root + dir;
};

exports.basename = function(path, ext) {
  var f = splitPath(path)[2];
  // TODO: make this comparison case-insensitive on windows?
  if (ext && f.substr(-1 * ext.length) === ext) {
    f = f.substr(0, f.length - ext.length);
  }
  return f;
};

exports.extname = function(path) {
  return splitPath(path)[3];
};
<commit_msg>* [bug] the splitPath RegExpr is wrong.<commit_after>// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

//var isWindows = process.platform === 'win32';
//var util = require('util');

var SEP = require("./codec");
//var PATH_SEP = SEP.PATH_SEP

function objectToString(o) {
  return Object.prototype.toString.call(o);
}

var isArray = Array.isArray;

function isBoolean(arg) {
  return typeof arg === 'boolean';
}

function isNullOrUndefined(arg) {
  return arg == null;
}
function isString(arg) {
  return typeof arg === 'string';
}

function isNumber(arg) {
  return typeof arg === 'number';
}

function isUndefined(arg) {
  return arg === void 0;
}

function isObject(arg) {
  return typeof arg === 'object' && arg !== null;
}

function isFunction(arg) {
  return typeof arg === 'function';
}

function isDate(d) {
  return isObject(d) && objectToString(d) === '[object Date]';
}
// resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
// if parts[0] is "." means relative path and allowAboveRoot.
function normalizeArray(parts, allowAboveRoot) {
  // if the path tries to go above the root, `up` ends up > 0
  var up = 0;
  if (isNullOrUndefined(allowAboveRoot)) {
      switch (parts[0]) {
        case '.':
            allowAboveRoot = true;
            break;
        case SEP.PATH_SEP:
            allowAboveRoot =false;
            parts.splice(0,1);
            break;
      }
  }
  for (var i = parts.length - 1; i >= 0; i--) {
    var last = parts[i];
    if (last === '.') {
      parts.splice(i, 1);
    } else if (last === '..') {
      parts.splice(i, 1);
      up++;
    } else if (up) {
      parts.splice(i, 1);
      up--;
    }
  }

  // if the path is allowed to go above the root, restore leading ..s
  if (allowAboveRoot) {
    for (; up--; up) {
      parts.unshift('..');
    }
  }

  return parts;
}

exports.normalizeArray = normalizeArray;

/* posix */

  // Split a filename into [root, dir, basename, ext], unix version
  // 'root' is just a slash, or nothing.
  //var splitPathRe =
  //    /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
  //    /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/
  var splitPathRe = new RegExp("^(\\"+SEP.PATH_SEP+"?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\"+SEP.PATH_SEP+"]+?|)(\\.[^.\\"+SEP.PATH_SEP+"]*|))(?:[\\"+SEP.PATH_SEP+"]*)$");
  var splitPath = function(filename) {
    return splitPathRe.exec(filename).slice(1);
  };

  // path.resolve([from ...], to)
  // posix version
  // return [resolvedAbsolute, parts...]
  // the arguments can be string or array
  resolveArray = exports.resolveArray = function() {
    var resolvedPath = [],
        resolvedAbsolute = false;

    for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
      var path = (i >= 0) ? arguments[i] : ".";

      // Skip empty and invalid entries
      if (isArray(path)) {
          if (path.length === 0) {
            //treat empty array as root path
            resolvedAbsolute = true;
          } else {
            resolvedPath = path.filter(Boolean).concat(resolvedPath);
            resolvedAbsolute = path[0] === "" || path[0] !== '.'
          }
          continue;
      } else if (!isString(path)) {
        throw new TypeError('Arguments to path.resolve must be strings');
      } else if (!path) {
        continue;
      }

      resolvedPath = path.split(SEP.PATH_SEP).filter(Boolean).concat(resolvedPath);
      //resolvedPath = path + '/' + resolvedPath;
      resolvedAbsolute = path.charAt(0) === SEP.PATH_SEP;
    }

    // At this point the path should be resolved to a full absolute path, but
    // handle relative paths to be safe (might happen when process.cwd() fails)

    // Normalize the path
    //resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) {
    //  return !!p;
    //}), !resolvedAbsolute).join('/');
    resolvedPath = normalizeArray(resolvedPath, !resolvedAbsolute);
    resolvedPath.unshift(resolvedAbsolute);
    return resolvedPath;
  };

  exports.resolve = function() {
    var resolvedPath = resolveArray.apply(null,arguments);
    var resolvedAbsolute = resolvedPath[0];
    resolvedPath.shift(0,1);
    return ((resolvedAbsolute ? SEP.PATH_SEP : '') + resolvedPath.join(SEP.PATH_SEP)) || '.';
  };

  // path.normalize(path)
  // posix version
  exports.normalize = function(path) {
    var isAbsolute = exports.isAbsolute(path),
        trailingSlash = path[path.length - 1] === SEP.PATH_SEP,
        segments = path.split(SEP.PATH_SEP),
        nonEmptySegments = [];

    // Normalize the path
    for (var i = 0; i < segments.length; i++) {
      if (segments[i]) {
        nonEmptySegments.push(segments[i]);
      }
    }
    path = normalizeArray(nonEmptySegments, !isAbsolute).join(SEP.PATH_SEP);

    if (!path && !isAbsolute) {
      path = '.';
    }
    if (path && trailingSlash) {
      path += SEP.PATH_SEP;
    }

    return (isAbsolute ? SEP.PATH_SEP : '') + path;
  };

  // posix version
  exports.isAbsolute = function(path) {
    return path.charAt(0) === SEP.PATH_SEP;
  };

  // path.join can mixture array and string arguments now!
  // path.join("path1", ["path2", "path3"], "path4")
  // = path1/path2/path3/path4
  exports.join = function() {
    var path = '';
    var vPathSep = SEP.PATH_SEP;
    for (var i = 0; i < arguments.length; i++) {
      var segment = arguments[i];
      // Skip empty and invalid entries
      if (isArray(segment)) {
          if (segment.length === 0 && path.length === 0) {
              path = vPathSep
          } else {
            segment = segment.filter(Boolean).join(vPathSep);
            if (segment) {
              path += vPathSep + segment;
            }
          }
          continue;
      } else if (!isString(segment)) {
        throw new TypeError('Arguments to path.resolve must be strings');
      } else if (!segment) {
        continue;
      }

      if (!isString(segment)) {
        throw new TypeError('Arguments to path.join must be strings');
      }
      if (segment) {
        if (!path) {
          path += segment;
        } else {
          path += vPathSep + segment;
        }
      }
    }
    return exports.normalize(path);
  };

  // path.relative(from, to)
  // posix version
  exports.relative = function(from, to) {
    var vPathSep = SEP.PATH_SEP;
    var fromParts = resolveArray(from);
    var toParts = resolveArray(to);
    fromParts.shift(0,1);
    toParts.shift(0,1);

    /*
    function trim(arr) {
      var start = 0;
      for (; start < arr.length; start++) {
        if (arr[start] !== '') break;
      }

      var end = arr.length - 1;
      for (; end >= 0; end--) {
        if (arr[end] !== '') break;
      }

      if (start > end) return [];
      return arr.slice(start, end + 1);
    }

    var fromParts = trim(from.split(vPathSep));
    var toParts = trim(to.split(vPathSep));
    */

    var length = Math.min(fromParts.length, toParts.length);
    var samePartsLength = length;
    var i;
    for (i = 0; i < length; i++) {
      if (fromParts[i] !== toParts[i]) {
        samePartsLength = i;
        break;
      }
    }

    var outputParts = [];
    for (i = samePartsLength; i < fromParts.length; i++) {
      outputParts.push('..');
    }

    outputParts = outputParts.concat(toParts.slice(samePartsLength));

    return outputParts.join(vPathSep);
  };

  exports.sep = SEP.PATH_SEP;
  exports.delimiter = ':';

exports.dirname = function(path) {
  var result = splitPath(path),
      root = result[0],
      dir = result[1];

  if (!root && !dir) {
    // No dirname whatsoever
    return '.';
  }

  if (dir) {
    // It has a dirname, strip trailing slash
    dir = dir.substr(0, dir.length - 1);
  }

  return root + dir;
};

exports.basename = function(path, ext) {
  var f = splitPath(path)[2];
  // TODO: make this comparison case-insensitive on windows?
  if (ext && f.substr(-1 * ext.length) === ext) {
    f = f.substr(0, f.length - ext.length);
  }
  return f;
};

exports.extname = function(path) {
  return splitPath(path)[3];
};
<|endoftext|>