Follower = {

  connect: function (urlSet) {

    var electorTries;
    // start each elector as untried/assumed connectable.
    var makeElectorTries = function (urlSet) {
      electorTries = {};
      if (typeof urlSet === 'string') {
        urlSet = _.map(urlSet.split(','), function (url) {return url.trim();});
      }
      _.each(urlSet, function (url) {
        electorTries[url] = 0;
      });
    };
    makeElectorTries(urlSet);
    var tryingUrl = null;
    var conn = null;
    var leader = null;
    var connected = null;
    var intervalHandle = null;

    var findFewestTries = function () {
      var min = 10000;
      var minElector = null;
      _.each(electorTries, function (tries, elector) {
        if (tries < min) {
          min = tries;
          minElector = elector;
        }
      });
      return minElector;
    };

    var updateElectorate = function (res) {
      leader = res.leader;
      _.each(electorTries, function (state, elector) {
        if (!_.contains(res.electorate, elector)) {
          delete electorTries[elector];
        }
      });
      _.each(res.electorate, function (elector) {
        if (typeof electorTries[elector] === 'undefined') {
          electorTries[elector] = 0; // we haven't heard of this elector yet.
        }
      });
    };

    var tryElector = function (url) {
      url = url || findFewestTries();
      console.log("trying", url, electorTries);
      if (conn) {
        conn._reconnectImpl({
          url: url
        });
      } else {
        conn = DDP.connect(url);
        conn._reconnectImpl = conn.reconnect;
      }

      if (tryingUrl) {
        electorTries[tryingUrl]++;
      } else {
        tryingUrl = url;
        conn.call('getElectorate', function (err, res) {
          connected = tryingUrl;
          tryingUrl = null;
          if (err) {
            electorTries[url]++;
            return;
          }
          // we got an answer!  Connected!
          electorTries[url] = 0;
          if (res.leader === url) {
            // we're good.

          } else {
            // let's connect to the leader anyway, if we think it
            // is connectable.
            if (electorTries[res.leader] == 0) {
              tryElector(res.leader);

            } else {
              // XXX: leader is probably down, we're probably going to elect
              // soon.  Wait for the next round.
            }

          }
          updateElectorate(res);
        });
      };
    };

    tryElector();

    var checkConnection = function () {
        if (conn.status().status !== 'connected' || connected !== leader) {
          tryElector();
        } else {
          conn.call('getElectorate', function (err, res) {
            if (err) {
              electorTries[connected]++;
              tryElector();
            } else {
              updateElectorate(res);
            }
          });
        }
    };

    var monitorConnection = function () {
      return Meteor.setInterval(checkConnection, 5*1000); // every 5 seconds
    };

    intervalHandle = monitorConnection();


    var prevDisconnect = conn.disconnect;
    conn.disconnect = function () {
      if (intervalHandle)
        Meteor.clearInterval(intervalHandle);
      intervalHandle = null;
      prevDisconnect.apply(conn);
    };

    conn.reconnect = function () {
      if (!intervalHandle)
        intervalHandle = monitorConnection();
      if (arguments[0] && arguments[0].url) {
        makeElectorTries(arguments[0].url);
        tryElector(arguments[0].url);
      } else {
        conn._reconnectImpl.apply(conn, arguments);
      }
    };

    return conn;

  }
};

@@ -1,8 +1,135 @@
+var fs = Npm.require('fs');%0A%0Avar readFile = Meteor._wrapAsync(fs.readFile);%0A%0Avar writeFile = Meteor._wrapAsync(fs.writeFile);%0A%0A
 Follower
@@ -165,13 +165,21 @@
 lSet
+, options
 ) %7B%0A
-%0A
     
@@ -192,24 +192,53 @@
 ectorTries;%0A
+    options = options %7C%7C %7B%7D;%0A
     // start
@@ -278,24 +278,91 @@
 connectable.
+%0A%0A    // for options.priority, low-priority things are tried first.
 %0A    var mak
@@ -393,20 +393,73 @@
  (urlSet
+, options
 ) %7B%0A
+      if (options.reset %7C%7C !electorTries)%0A  
       el
@@ -660,32 +660,52 @@
 ctorTries%5Burl%5D =
+ options.priority %7C%7C
  0;%0A      %7D);%0A  
@@ -717,33 +717,422 @@
     
-makeElectorTries(urlSet);
+if (options.file) %7B%0A      var contents;%0A      try %7B%0A        contents = readFile(options.file, 'utf8');%0A      %7D catch (e) %7B%0A        console.log(%22no file to read electors out of%22);%0A      %7D%0A      if (contents)%0A        makeElectorTries(contents, %7B priority: 0, reset: true %7D);%0A      makeElectorTries(urlSet, %7Bpriority: 1, reset: false%7D);%0A    %7D else %7B%0A      makeElectorTries(urlSet, %7B priority: 0, reset: true %7D);%0A    %7D
 %0A   
@@ -1980,24 +1980,125 @@
 %7D%0A      %7D);%0A
+      if (options.file) %7B%0A        writeFile(options.file, res.electorate.join(','), 'utf8');%0A      %7D%0A
     %7D;%0A%0A    
@@ -2214,16 +2214,27 @@
 torTries
+, tryingUrl
 );%0A     
@@ -2464,24 +2464,49 @@
 yingUrl%5D++;%0A
+        tryingUrl = url;%0A
       %7D else
@@ -4327,32 +4327,60 @@
 arguments%5B0%5D.url
+, %7Breset: true, priority: 0%7D
 );%0A        tryEl

allow setting priorities on electors