(function($, wp, wps, window, undefined) {
	'$:nomunge';
	var $w = $(window),
	waypoints = [],
	oldScroll = -99999,
	didScroll = false,
	didResize = false,
	eventName = 'waypoint.reached',
	methods = {
		init: function(f, options) {
			this.each(function() {
				var $this = $(this),
				ndx = waypointIndex($this),
				base = ndx < 0 ? $.fn[wp].defaults: waypoints[ndx].options,
				opts = $.extend({},
				base, options);
				opts.offset = opts.offset === "bottom-in-view" ?
				function() {
					return $[wps]('viewportHeight') - $(this).outerHeight();
				}: opts.offset;
				if (ndx < 0) {
					waypoints.push({
						element: $this,
						offset: $this.offset().top,
						options: opts
					});
				}
				 else {
					waypoints[ndx].options = opts;
				}
				f && $this.bind(eventName, f);
			});
			$[wps]('refresh');
			return this;
		},
		remove: function() {
			return this.each(function() {
				var ndx = waypointIndex($(this));
				if (ndx >= 0) {
					waypoints.splice(ndx, 1);
				}
			});
		},
		destroy: function() {
			return this.unbind(eventName)[wp]('remove');
		}
	};
	function waypointIndex(el) {
		var i = waypoints.length - 1;
		while (i >= 0 && waypoints[i].element[0] !== el[0]) {
			i -= 1;
		}
		return i;
	}
	function triggerWaypoint(way, dir) {
		way.element.trigger(eventName, dir)
		 if (way.options.triggerOnce) {
			way.element[wp]('destroy');
		}
	}
	function doScroll() {
		var newScroll = $w.scrollTop(),
		isDown = newScroll > oldScroll,
		pointsHit = $.grep(waypoints,
		function(el, i) {
			return isDown ? (el.offset > oldScroll && el.offset <= newScroll) : (el.offset <= oldScroll && el.offset > newScroll);
		});
		if (!oldScroll || !newScroll) {
			$[wps]('refresh');
		}
		oldScroll = newScroll;
		if (!pointsHit.length) return;
		if ($[wps].settings.continuous) {
			$.each(isDown ? pointsHit: pointsHit.reverse(),
			function(i, point) {
				triggerWaypoint(point, [isDown ? 'down': 'up']);
			});
		}
		 else {
			triggerWaypoint(pointsHit[isDown ? pointsHit.length - 1: 0], [isDown ? 'down': 'up']);
		}
	}
	$.fn[wp] = function(method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		}
		 else if (typeof method === "function" || !method) {
			return methods.init.apply(this, arguments);
		}
		 else if (typeof method === "object") {
			return methods.init.apply(this, [null, method]);
		}
		 else {
			$.error('Method ' + method + ' does not exist on jQuery' + wp);
		}
	};
	$.fn[wp].defaults = {
		offset: 0,
		triggerOnce: false
	};
	var jQMethods = {
		refresh: function() {
			$.each(waypoints,
			function(i, o) {
				var adjustment = 0,
				oldOffset = o.offset;
				if (typeof o.options.offset === "function") {
					adjustment = o.options.offset.apply(o.element);
				}
				 else if (typeof o.options.offset === "string") {
					var amount = parseFloat(o.options.offset),
					adjustment = o.options.offset.indexOf("%") ? Math.ceil($[wps]('viewportHeight') * (amount / 100)) : amount;
				}
				 else {
					adjustment = o.options.offset;
				}
				o.offset = o.element.offset().top - adjustment;
				if (oldScroll > oldOffset && oldScroll <= o.offset) {
					triggerWaypoint(o, ['up']);
				}
				 else if (oldScroll < oldOffset && oldScroll >= o.offset) {
					triggerWaypoint(o, ['down']);
				}
			});
			waypoints.sort(function(a, b) {
				return a.offset - b.offset;
			});
		},
		viewportHeight: function() {
			return (window.innerHeight ? window.innerHeight: $w.height());
		},
		aggregate: function() {
			var points = $();
			$.each(waypoints,
			function(i, e) {
				points = points.add(e.element);
			});
			return points;
		}
	};
	$[wps] = function(method) {
		if (jQMethods[method]) {
			return jQMethods[method].apply(this);
		}
		 else {
			return jQMethods["aggregate"]();
		}
	};
	$[wps].settings = {
		continuous: true,
		resizeThrottle: 200,
		scrollThrottle: 100
	};
	$w.scroll(function() {
		if (!didScroll) {
			didScroll = true;
			window.setTimeout(function() {
				doScroll();
				didScroll = false;
			},
			$[wps].settings.scrollThrottle);
		}
	}).resize(function() {
		if (!didResize) {
			didResize = true;
			window.setTimeout(function() {
				$[wps]('refresh');
				didResize = false;
			},
			$[wps].settings.resizeThrottle);
		}
	}).load(function() {
		$[wps]('refresh');
		doScroll();
	});
})(jQuery, 'waypoint', 'waypoints', this);