(function($) {
  'use strict';

  // cache window as jQuery object
  var $window = $(window);

  var ScrollWatch = function(el, options) {
    _.bindAll(this, 'handleScroll');

    this.el = el;
    this.$el = $(el);

    this.options = _.defaults(options || {}, {
      throttle: 100
    });

    this.inViewport = false;
    this.callbacks = { "scrollin": $.Callbacks(), "scrollout": $.Callbacks() };
    this.setupEvents();
  };

  ScrollWatch.prototype = {

    setupEvents: function() {
      this._handleScroll = _.throttle(this.handleScroll, this.options.throttle);
      $window.on('scroll', this._handleScroll)
    },

    on: function(event, options, callback, thisArg) {
      if (_.isFunction(options)) {
        callback = options;
        thisArg = callback;
        options = {};
      }

      options = _.extend({}, this.options, options);
      callback = _.bind(callback, thisArg || this.$el);

      // delay handler
      if (options.delay) {
        callback = this._createDelayedCallback(event, callback, options);
      }

      this.callbacks[event].add(callback);
      $window.scroll();
      return this;
    },

    _createDelayedCallback: function(event, cb, options) {
        return function() {
          var args = arguments;
          _.delay(function() {
                cb.apply(null, args)
            }, options.delay);
        };
    },

    handleScroll: function() {
      if (!this.callbacks) { return; }

      var inViewport = this.isInViewport();
      var currentOffset = $window.scrollTop();

      if (!this.lastOffset) {
        this.direction = false;
      } else {
          this.direction = (currentOffset > this.lastOffset) ? 'down' : 'up';
      }

      this.lastOffset = currentOffset;

      if (!this.inViewport && inViewport > 0.9) {
        this.inViewport = true;
        this.trigger('scrollin');
      } else if (this.inViewport && !inViewport) {
        this.inViewport = false;

        if (this.dfd) {
          this.dfd.done(_.bind(this.trigger, this, 'scrollout'))
        } else {
          this.trigger('scrollout');
        }
      }

      return this;
    },

    trigger: function(event)
    {
      if (event == this.lastTriggered) {
        return false;
      }

      this.lastTriggered = event;
      this.callbacks[event].fire({ direction: this.direction });
    },

    isInViewport: function() {
      var scrollTop = $window.scrollTop();
      var windowHeight = $window.height();
      var scrollBottom = scrollTop + windowHeight;

      var elTop = this.$el.offset().top;
      var elHeight = this.$el.outerHeight();
      var elBottom = elTop + elHeight;

      // element bigger than viewport size and off screen
      if (elHeight > windowHeight && scrollTop > elTop && scrollBottom < elBottom) {
        return 1;
      }

      // element small then viewport fully in view
      if (elHeight < windowHeight && elTop > scrollTop && elBottom < scrollBottom) {
        return 1;
      }

      // element bleeding off the bottom of the viewport
      if (elTop > scrollTop && elTop < scrollBottom) {
        return (scrollBottom - elTop) / elHeight;
      }

      // element bleeding off the top of the viewport
      if (elBottom > scrollTop && elBottom < scrollBottom) {
        return (scrollTop - elBottom) / elHeight;
      }

      return 0;
    },

    off: function() {
      $window.off('scroll', this._handleScroll);
    }

  };

  window.ScrollWatch = ScrollWatch;

  $.fn.scrollWatch = function(options) {
    var $this = $(this),
        data = $this.data('scrollWatch');

    if (!data) {
      $this.data('scrollWatch', (data = new ScrollWatch(this, options)));
    }

    return data;
  };

}(jQuery));

@@ -378,16 +378,41 @@
 ollout%22:
+ $.Callbacks(), %22scroll%22:
  $.Callb
@@ -1477,26 +1477,70 @@
     var 
-inViewport
+lastVisibility = this.visibility;%0A      var visibility
  = this.
@@ -1684,26 +1684,24 @@
 e %7B%0A        
-  
 this.directi
@@ -1835,26 +1835,26 @@
 port && 
-inViewport
+visibility
  %3E 0.9) 
@@ -1958,26 +1958,26 @@
 ort && !
-inViewport
+visibility
 ) %7B%0A    
@@ -2160,32 +2160,162 @@
      %7D%0A      %7D%0A%0A
+      if (visibility !== lastVisibility) %7B%0A        this.visibility = visibility;%0A        this.trigger('scroll');        %0A      %7D%0A%0A
       return thi
@@ -2353,20 +2353,16 @@
 n(event)
-%0A   
  %7B%0A     
@@ -2372,16 +2372,39 @@
  (event 
+!== 'scroll' && event =
 == this.
@@ -2441,34 +2441,42 @@
 n false;%0A      %7D
-%0A%0A
+ else %7B%0A  
       this.lastT
@@ -2493,16 +2493,25 @@
  event;%0A
+      %7D%0A%0A
       th
@@ -2562,16 +2562,45 @@
 irection
+, visibility: this.visibility
  %7D);%0A   

Add scroll event