docs: function wrapAsyncCallToAllPages(coll, func, args, callbackWrapper){
    var page = _.pick(coll, [
      'href', 'query', 'offset', 'limit', 'items',
      'dataStore', 'instanceConstructor']);
  
    var callback = args.pop();
  
    function getNextPage(page, callback) {
      // There is no next page.
      if (page.items.length < page.limit) {
        return callback();
      }
  
      // We've fully exhausted the current page. There could be another one on the server, so
      // we have to execute another query to continue to the next page if one exists.
      var nextQuery = utils.shallowCopy(page.query, {});
      nextQuery.offset = page.offset + page.items.length;
      nextQuery.limit = 100;
  
      page.dataStore.getResource(page.href, nextQuery, page.instanceConstructor,
        function onNextPage(err, collectionResource) {
          if (err) {
            return callback(err);
          }
          (typeof setImmediate !== 'undefined' ?
            setImmediate : process.nextTick)(function(){
            callback(null, collectionResource);
          });
        });
    }
  
    function worker(task, cb){
      if (!task.collection.items || !task.collection.items.length){
        return cb();
      }
  
      async.parallel([
        function(parallel_cb){
          if (callbackWrapper.isDone){
            return parallel_cb();
          }
  
          var callArgs = Array.prototype
            .concat(
              [task.collection.items],
              !!callbackWrapper.wrapPageArgs ? callbackWrapper.wrapPageArgs(args) : args,
              callbackWrapper.wrapPageCallback(parallel_cb.bind(this, null)));
          func.apply(this, callArgs);
        },
        function(parallel_cb){
          if (callbackWrapper.isDone){
            return parallel_cb();
          }
  
          getNextPage(task.collection, function(err, nextPage){
            if (err || !nextPage){
              return parallel_cb(err);
            }
  
            q.push({collection: nextPage});
            parallel_cb();
          });
        }
      ], cb);
  
    }
  
    var q = async.queue(worker, 1);
    q.drain = callbackWrapper.wrapCallback(callback);
    q.push({ collection: page });
  }