SubManager = function (options) {
  var self = this;
  self.cache = {};
  self.ready = false;

  self.dep = new Deps.Dependency();

  self.computation = Deps.autorun(function() {
    var ready = true;
    _.each(self.cache, function(args) {
      ready = ready && Meteor.subscribe.apply(Meteor, args).ready();
    });

    if(ready) {
      self.ready = true;
      self.dep.changed();
    }
  });
};

SubManager.prototype.subscribe = function() {
  var self = this;
  if(Meteor.isClient) {
    var hash = JSON.stringify(arguments);
    this.cache[hash] = arguments;

    this.ready = false;
    this.computation.invalidate();

    return {
      ready: function() {
        self.dep.depend();
        return self.ready;
      }
    };
  } else {
    // to support fast-render
    if(Meteor.subscribe) {
      return Meteor.subscribe.apply(Meteor, arguments);
    }
  }
};

@@ -57,18 +57,291 @@
 elf.
-cache = %7B%7D
+options = options %7C%7C %7B%7D;%0A  // maxiumum number of subscriptions are cached%0A  self.options.cacheLimit = self.options.cacheLimit %7C%7C 10;%0A  // maximum time, subscription stay in the cache%0A  self.options.expireIn = self.options.expireIn %7C%7C 5;%0A%0A  self._cacheMap = %7B%7D;%0A  self._cacheList = %5B%5D
 ;%0A  
@@ -360,17 +360,16 @@
  false;%0A
-%0A
   self.d
@@ -440,24 +440,84 @@
 unction() %7B%0A
+    self._applyCacheLimit();%0A    self._applyExpirations();%0A%0A
     var read
@@ -542,21 +542,26 @@
 ch(self.
+_
 cache
+List
 , functi
@@ -563,20 +563,19 @@
 unction(
-args
+sub
 ) %7B%0A    
@@ -624,16 +624,20 @@
 Meteor, 
+sub.
 args).re
@@ -832,69 +832,21 @@
     
-var hash = JSON.stringify(arguments);%0A    this.cache%5Bhash%5D = 
+this._addSub(
 argu
@@ -850,18 +850,18 @@
 rguments
+)
 ;
-%0A
 %0A    thi
@@ -1154,12 +1154,1183 @@
    %7D%0A  %7D%0A%7D;%0A
+%0ASubManager.prototype._addSub = function(args) %7B%0A  var hash = JSON.stringify(args);%0A  if(!this._cacheMap%5Bhash%5D) %7B%0A    var sub = %7B%0A      args: args,%0A      hash: hash%0A    %7D;%0A%0A    this._cacheMap%5Bhash%5D = sub;%0A    this._cacheList.push(sub);%0A  %7D%0A%0A  // add the current sub to the top of the list%0A  var sub = this._cacheMap%5Bhash%5D;%0A  sub.updated = Date.now();%0A%0A  var index = this._cacheList.indexOf(sub);%0A  this._cacheList.splice(index, 1);%0A  this._cacheList.push(sub);%0A%7D;%0A%0ASubManager.prototype._applyCacheLimit = function () %7B%0A  var self = this;%0A  var overflow = self._cacheList.length - self.options.cacheLimit;%0A  if(overflow %3E 0) %7B%0A    var removedSubs = self._cacheList.splice(0, overflow);%0A    _.each(removedSubs, function(sub) %7B%0A      delete self._cacheMap%5Bsub.hash%5D;%0A    %7D);%0A  %7D%0A%7D;%0A%0A%0ASubManager.prototype._applyExpirations = function() %7B%0A  var self = this;%0A  var newCacheList = %5B%5D;%0A%0A  var expirationTime = Date.now() - self.options.expirationTime * 60 * 1000;%0A  _.each(self._cacheList, function(sub) %7B%0A    if(sub.updated %3E= expirationTime) %7B%0A      newCacheList.push(sub);%0A    %7D else %7B%0A      delete self._cacheMap%5Bsub.hash%5D;%0A    %7D%0A  %7D);%0A%0A  self._cacheList = newCacheList;%0A%7D;%0A

add expireIn and cacheLimit support