text:    /**
     *  Runs all observable sequences in parallel and collect their last elements.
     *
     * @example
     *  1 - res = Rx.Observable.forkJoin([obs1, obs2]);
     *  1 - res = Rx.Observable.forkJoin(obs1, obs2, ...);
     * @returns {Observable} An observable sequence with an array collecting the last elements of all the input sequences.
     */
    Observable.forkJoin = function () {
      var allSources = [];
      if (Array.isArray(arguments[0])) {
        allSources = arguments[0];
      } else {
        for(var i = 0, len = arguments.length; i < len; i++) { allSources.push(arguments[i]); }
      }
      return new AnonymousObservable(function (subscriber) {
        var count = allSources.length;
        if (count === 0) {
          subscriber.onCompleted();
          return disposableEmpty;
        }
        var group = new CompositeDisposable(),
          finished = false,
          hasResults = new Array(count),
          hasCompleted = new Array(count),
          results = new Array(count);
  
        for (var idx = 0; idx < count; idx++) {
          (function (i) {
            var source = allSources[i];
            isPromise(source) && (source = observableFromPromise(source));
            group.add(
              source.subscribe(
                function (value) {
                if (!finished) {
                  hasResults[i] = true;
                  results[i] = value;
                }
              },
              function (e) {
                finished = true;
                subscriber.onError(e);
                group.dispose();
              },
              function () {
                if (!finished) {
                  if (!hasResults[i]) {
                      subscriber.onCompleted();
                      return;
                  }
                  hasCompleted[i] = true;
                  for (var ix = 0; ix < count; ix++) {
                    if (!hasCompleted[ix]) { return; }
                  }
                  finished = true;
                  subscriber.onNext(results);
                  subscriber.onCompleted();
                }
              }));
          })(idx);
        }
  
        return group;
      });
    };
  