  /**
   *  Projects each element of an observable sequence into a window that is completed when either it's full or a given amount of time has elapsed.
   *  @example
   *  1 - res = source.windowWithTimeOrCount(5000, 50); // 5s or 50 items
   *  2 - res = source.windowWithTimeOrCount(5000, 50, scheduler); //5s or 50 items
   *      
   * @memberOf Observable#
   * @param {Number} timeSpan Maximum time length of a window.
   * @param {Number} count Maximum element count of a window.
   * @param {Scheduler} [scheduler]  Scheduler to run windowing timers on. If not specified, the timeout scheduler is used.
   * @returns {Observable} An observable sequence of windows.
   */
  observableProto.windowWithTimeOrCount = function (timeSpan, count, scheduler) {
    var source = this;
    isScheduler(scheduler) || (scheduler = timeoutScheduler);
    return new AnonymousObservable(function (observer) {
      var createTimer,
        groupDisposable,
        n = 0,
        refCountDisposable,
        s = new Subject()
        timerD = new SerialDisposable(),
        windowId = 0;
      groupDisposable = new CompositeDisposable(timerD);
      refCountDisposable = new RefCountDisposable(groupDisposable);

      observer.onNext(addRef(s, refCountDisposable));
      createTimer(0);
      groupDisposable.add(source.subscribe(function (x) {
        var newId = 0, newWindow = false;
        s.onNext(x);
        n++;
        if (n === count) {
          newWindow = true;
          n = 0;
          newId = ++windowId;
          s.onCompleted();
          s = new Subject();
          observer.onNext(addRef(s, refCountDisposable));
        }
        newWindow && createTimer(newId);
      }, function (e) {
        s.onError(e);
        observer.onError(e);
      }, function () {
        s.onCompleted();
        observer.onCompleted();
      }));       

      return refCountDisposable;    

      function createTimer(id) {
        var m = new SingleAssignmentDisposable();
        timerD.setDisposable(m);
        m.setDisposable(scheduler.scheduleWithRelative(timeSpan, function () {
          var newId;
          if (id !== windowId) { return; }
          n = 0;
          newId = ++windowId;
          s.onCompleted();
          s = new Subject();
          observer.onNext(addRef(s, refCountDisposable));
          createTimer(newId);
        }));
      }       
    });
  };
