function all(promises) {
    var result = new Promise(),
        counter = 0,
        results = isArray(promises) ? [] : {};

    forEach(promises, function(promise, key) {
      counter++;
      when(promise).then(function(value) {
        results[key] = value;
        if (!(--counter)) resolvePromise(result, results);
      }, function(reason) {
        rejectPromise(result, reason);
      });
    });

    if (counter === 0) {
      resolvePromise(result, results);
    }

    return result;
  }
@ngdoc method
@name $q#all
@kind function

@description
Combines multiple promises into a single promise that is resolved when all of the input
promises are resolved.

@param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
@returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
  each value corresponding to the promise at the same index/key in the `promises` array/hash.
  If any of the promises is resolved with a rejection, this resulting promise will be rejected
  with the same rejection value.