text: /*! @license Firebase v4.1.1
  Build: rev-ca0d1df
  Terms: https://firebase.google.com/terms/ */
  
  'use strict';
  
  Object.defineProperty(exports, "__esModule", {
      value: true
  });
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  
  exports.createSubscribe = createSubscribe;
  exports.async = async;
  
  var _shared_promise = require('./shared_promise');
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  var LocalPromise = _shared_promise.local.Promise;
  /**
   * Helper to make a Subscribe function (just like Promise helps make a
   * Thenable).
   *
   * @param executor Function which can make calls to a single Observer
   *     as a proxy.
   * @param onNoObservers Callback when count of Observers goes to zero.
   */
  function createSubscribe(executor, onNoObservers) {
      var proxy = new ObserverProxy(executor, onNoObservers);
      return proxy.subscribe.bind(proxy);
  }
  /**
   * Implement fan-out for any number of Observers attached via a subscribe
   * function.
   */
  
  var ObserverProxy = function () {
      /**
       * @param executor Function which can make calls to a single Observer
       *     as a proxy.
       * @param onNoObservers Callback when count of Observers goes to zero.
       */
      function ObserverProxy(executor, onNoObservers) {
          var _this = this;
  
          _classCallCheck(this, ObserverProxy);
  
          this.observers = [];
          this.unsubscribes = [];
          this.observerCount = 0;
          // Micro-task scheduling by calling task.then().
          this.task = LocalPromise.resolve();
          this.finalized = false;
          this.onNoObservers = onNoObservers;
          // Call the executor asynchronously so subscribers that are called
          // synchronously after the creation of the subscribe function
          // can still receive the very first value generated in the executor.
          this.task.then(function () {
              executor(_this);
          }).catch(function (e) {
              _this.error(e);
          });
      }
  
      _createClass(ObserverProxy, [{
          key: 'next',
          value: function next(value) {
              this.forEachObserver(function (observer) {
                  observer.next(value);
              });
          }
      }, {
          key: 'error',
          value: function error(_error) {
              this.forEachObserver(function (observer) {
                  observer.error(_error);
              });
              this.close(_error);
          }
      }, {
          key: 'complete',
          value: function complete() {
              this.forEachObserver(function (observer) {
                  observer.complete();
              });
              this.close();
          }
          /**
           * Subscribe function that can be used to add an Observer to the fan-out list.
           *
           * - We require that no event is sent to a subscriber sychronously to their
           *   call to subscribe().
           */
  
      }, {
          key: 'subscribe',
          value: function subscribe(nextOrObserver, error, complete) {
              var _this2 = this;
  
              var observer = void 0;
              if (nextOrObserver === undefined && error === undefined && complete === undefined) {
                  throw new Error("Missing Observer.");
              }
              // Assemble an Observer object when passed as callback functions.
              if (implementsAnyMethods(nextOrObserver, ['next', 'error', 'complete'])) {
                  observer = nextOrObserver;
              } else {
                  observer = {
                      next: nextOrObserver,
                      error: error,
                      complete: complete
                  };
              }
              if (observer.next === undefined) {
                  observer.next = noop;
              }
              if (observer.error === undefined) {
                  observer.error = noop;
              }
              if (observer.complete === undefined) {
                  observer.complete = noop;
              }
              var unsub = this.unsubscribeOne.bind(this, this.observers.length);
              // Attempt to subscribe to a terminated Observable - we
              // just respond to the Observer with the final error or complete
              // event.
              if (this.finalized) {
                  this.task.then(function () {
                      try {
                          if (_this2.finalError) {
                              observer.error(_this2.finalError);
                          } else {
                              observer.complete();
                          }
                      } catch (e) {
                          // nothing
                      }
                  });
              }
              this.observers.push(observer);
              return unsub;
          }
          // Unsubscribe is synchronous - we guarantee that no events are sent to
          // any unsubscribed Observer.
  
      }, {
          key: 'unsubscribeOne',
          value: function unsubscribeOne(i) {
              if (this.observers === undefined || this.observers[i] === undefined) {
                  return;
              }
              delete this.observers[i];
              this.observerCount -= 1;
              if (this.observerCount === 0 && this.onNoObservers !== undefined) {
                  this.onNoObservers(this);
              }
          }
      }, {
          key: 'forEachObserver',
          value: function forEachObserver(fn) {
              if (this.finalized) {
                  // Already closed by previous event....just eat the additional values.
                  return;
              }
              // Since sendOne calls asynchronously - there is no chance that
              // this.observers will become undefined.
              for (var i = 0; i < this.observers.length; i++) {
                  this.sendOne(i, fn);
              }
          }
          // Call the Observer via one of it's callback function. We are careful to
          // confirm that the observe has not been unsubscribed since this asynchronous
          // function had been queued.
  
      }, {
          key: 'sendOne',
          value: function sendOne(i, fn) {
              var _this3 = this;
  
              // Execute the callback asynchronously
              this.task.then(function () {
                  if (_this3.observers !== undefined && _this3.observers[i] !== undefined) {
                      try {
                          fn(_this3.observers[i]);
                      } catch (e) {
                          // Ignore exceptions raised in Observers or missing methods of an
                          // Observer.
                          // Log error to console. b/31404806
                          if (typeof console !== "undefined" && console.error) {
                              console.error(e);
                          }
                      }
                  }
              });
          }
      }, {
          key: 'close',
          value: function close(err) {
              var _this4 = this;
  
              if (this.finalized) {
                  return;
              }
              this.finalized = true;
              if (err !== undefined) {
                  this.finalError = err;
              }
              // Proxy is no longer needed - garbage collect references
              this.task.then(function () {
                  _this4.observers = undefined;
                  _this4.onNoObservers = undefined;
              });
          }
      }]);
  
      return ObserverProxy;
  }();
  /** Turn synchronous function into one called asynchronously. */
  
  
  function async(fn, onError) {
      return function () {
          for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
              args[_key] = arguments[_key];
          }
  
          LocalPromise.resolve(true).then(function () {
              fn.apply(undefined, args);
          }).catch(function (error) {
              if (onError) {
                  onError(error);
              }
          });
      };
  }
  /**
   * Return true if the object passed in implements any of the named methods.
   */
  function implementsAnyMethods(obj, methods) {
      if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) !== 'object' || obj === null) {
          return false;
      }
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;
  
      try {
          for (var _iterator = methods[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
              var method = _step.value;
  
              if (method in obj && typeof obj[method] === 'function') {
                  return true;
              }
          }
      } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
      } finally {
          try {
              if (!_iteratorNormalCompletion && _iterator.return) {
                  _iterator.return();
              }
          } finally {
              if (_didIteratorError) {
                  throw _iteratorError;
              }
          }
      }
  
      return false;
  }
  function noop() {
      // do nothing
  }
  //# sourceMappingURL=subscribe.js.map
  