docs: function (fn) {
      var self = this;
  
      var evtCount = 0;
      var eventQueue = [];
      var eventQueueHandling = false;
  
      var errs = [];
      var doneCalled = false;
      var doneClb = null;
  
      var revisionMap = {};
      var collections = {};
  
      var lastEvent;
  
      var seenEvents = {};
  
      var replay = function (evt) {
        var evtId = dotty.get(evt, self.definition.id);
        lastEvent = evt;
        var concatenatedId;
        if (!!self.definition.revision && dotty.exists(evt, self.definition.revision) &&
          !!self.definition.aggregateId && dotty.exists(evt, self.definition.aggregateId)) {
          concatenatedId = self.getConcatenatedId(evt);
          revisionMap[concatenatedId] = dotty.get(evt, self.definition.revision);
        }
  
        var concatenatedWithEventId = evtId;
        if (concatenatedId) concatenatedWithEventId = concatenatedId + ':' + evtId;
        if (seenEvents[concatenatedWithEventId]) return;
        seenEvents[concatenatedWithEventId] = true;
  
        var target = self.dispatcher.getTargetInformation(evt);
  
        var viewBuilders = [], foundPrioSet = false;
  
        _.each(self.dispatcher.tree.getViewBuilders(target), function (vb) {
          if (!vb.collection.noReplay) {
            viewBuilders.push(vb);
  
            if (!foundPrioSet && vb.priority < Infinity) {
              foundPrioSet = true;
            }
  
            if (!collections[vb.collection.workerId]) {
              vb.collection.isReplaying = true;
              collections[vb.collection.workerId] = vb.collection;
            }
          }
        });
  
        if (foundPrioSet) {
          _.each(viewBuilders, function (vb) {
            eventQueue.push({event: evt, viewBuilders: [vb]});
            evtCount++;
          });
        } else {
          eventQueue.push({event: evt, viewBuilders: viewBuilders});
          evtCount += viewBuilders.length;
        }
  
        function handleNext () {
          if (evtCount <= 0 && doneCalled) {
            doneLater();
            return;
          }
  
          if (eventQueue.length > 0) {
            var task = eventQueue.shift();
            var e = task.event, vbs = task.viewBuilders;
  
            async.series([
              function (clb) {
                var preEventExtender = self.dispatcher.tree.getPreEventExtender(self.dispatcher.getTargetInformation(e));
                if (!preEventExtender) return clb(null);
                preEventExtender.extend(e, function (err, extEvt) {
                  if (err) return clb(err);
                  e = extEvt || e;
                  clb(null);
                });
              },
              function (clb) {
                async.each(vbs, function (vb, callback) {
                  vb.denormalize(e, function (err) {
                    --evtCount;
                    if (err) {
                      debug(err);
                      errs.push(err);
                    }
  
                    callback();
                  });
                }, clb);
              }
            ], function () {
              handleNext();
            });
          } else if (eventQueueHandling) {
            eventQueueHandling = false;
          }
        }
  
        if (!eventQueueHandling) {
          eventQueueHandling = true;
          process.nextTick(handleNext);
        }
      };
  
      function doneLater() {
        if (doneCalled) {
          done(doneClb);
        }
      }
  
      var done = function (callback) {
        if (evtCount > 0) {
          doneCalled = true;
          doneClb = callback;
          return;
        }
  
        async.parallel([
          function (callback) {
            async.each(_.values(collections), function (col, callback) {
              col.saveReplayingVms(callback);
            }, callback);
          },
          function (callback) {
            self.updateRevision(revisionMap, callback);
          },
          function (callback) {
            self.store.saveLastEvent(lastEvent, callback);
          }
        ], function (err) {
          seenEvents = {};
  
          if (err) {
            debug(err);
            errs.push(err);
          }
  
          if (errs.length === 0) {
            if (callback) {
              callback(null);
            }
            return;
          }
  
          if (callback) {
            callback(errs);
          }
        });
      };
  
      fn(replay, done);
    }