docs: function AddOnHandler(options) {
      var app = new Express(),
          refreshInterval = options.tokenRefreshInterval || DEFAULT_TOKEN_REFRESH_INTERVAL,
          gmeConfig = options.gmeConfig || webgme.getGmeConfig(),
          logger = webgme.Logger.create('gme:bin:addon-handler', gmeConfig.bin.log, false),
          webgmeUrl = options.webgmeUrl || 'http://127.0.0.1:' + gmeConfig.server.port,
          webgmeToken,
          timeoutId,
          mt,
          server;
  
      options.port = options.port || (gmeConfig.server.port + 1);
      options.path = options.path || '';
  
      function refreshToken() {
          var deferred = Q.defer(),
              req;
  
          if (webgmeToken) {
              logger.info('Token exists... ');
              req = superagent.get(webgmeUrl + '/api/user/token')
                  .set('Authorization', 'Bearer ' + webgmeToken);
          } else if (options.credentials) {
              logger.info('Credentials were given.. ');
              req = superagent.get(webgmeUrl + '/api/user/token')
                  .set('Authorization', 'Basic ' + Buffer.from(options.credentials).toString('base64'));
          } else {
              deferred.resolve();
              return deferred.promise;
          }
  
          logger.info('...will request new token at', webgmeUrl + '/api/user/token');
          req.end(function (err, res) {
              if (err) {
                  deferred.reject(err);
              } else if (typeof res.body.webgmeToken === 'string') {
                  webgmeToken = res.body.webgmeToken;
                  logger.info('Obtained new token from webgme server.');
                  mt.setToken(webgmeToken);
  
                  deferred.resolve();
              } else {
                  deferred.reject(new Error(webgmeUrl + '/user/token did not provide webgmeToken.'));
              }
  
              timeoutId = setTimeout(refreshToken, refreshInterval);
          });
  
          return deferred.promise;
      }
  
      this.start = function (callback) {
          var deferred = Q.defer(),
              statusUrl = options.path;
  
          if (statusUrl[statusUrl.length - 1] === '/') {
              statusUrl = statusUrl.substring(0, statusUrl.length - 1);
          }
  
          statusUrl = statusUrl + '/status';
  
          logger.debug('statusUrl', statusUrl);
  
          mt = new ManagerTracker(logger, gmeConfig, options);
  
          app.use(bodyParser.json());
  
          app.get(statusUrl, function (req, res, next) {
              try {
                  res.json(mt.getStatus({}));
              } catch (err) {
                  next(err);
              }
          });
  
          app.post(options.path, function (req, res, next) {
              var params = req.body;
  
              if (params.event === CONSTANTS.STORAGE.BRANCH_JOINED ||
                  params.event === CONSTANTS.STORAGE.BRANCH_HASH_UPDATED) {
                  mt.connectedWorkerStart(webgmeToken || params.webgmeToken, params.projectId, params.branchName)
                      .then(function (info) {
                          logger.info('connectedWorkerStart', params.projectId, params.branchName, JSON.stringify(info));
                          res.sendStatus(200);
                      })
                      .catch(function (err) {
                          logger.error(err);
                          next(err);
                      });
              //} else if (params.event === CONSTANTS.STORAGE.BRANCH_LEFT) {
              //    mt.connectedWorkerStop(params.projectId, params.branchName)
              //        .then(function (info) {
              //            logger.info('connectedWorkerStop', params.projectId, params.branchName, JSON.stringify(info));
              //            res.sendStatus(200);
              //        })
              //        .catch(function (err) {
              //            logger.error(err);
              //            next(err);
              //        });
              } else {
                  logger.error('Unknown command received');
                  res.sendStatus(404);
              }
          });
  
          webgmeToken = options.token;
  
          refreshToken()
              .finally(function (err) {
                  if (err) {
                      logger.warn('Error at initial token refresh, will still proceed', err);
                  }
  
                  server = app.listen(options.port);
                  logger.info('Will connect to webgme server at', webgmeUrl);
                  logger.info('Server listening at:  http://127.0.0.1:' + options.port, '...');
  
                  if (webgmeToken) {
                      logger.info('Credentials and/or token provided, will refresh token every',
                          refreshInterval, '[ms].');
                  }
  
                  deferred.resolve();
              });
  
          return deferred.promise.nodeify(callback);
      };
  
      this.stop = function (callback) {
          var deferred = Q.defer();
  
          clearTimeout(timeoutId);
          if (server) {
              server.close();
          }
  
          if (mt) {
              mt.close()
                  .then(deferred.resolve)
                  .catch(deferred.reject);
          } else {
              deferred.resolve();
          }
  
  
          return deferred.promise.nodeify(callback);
      };
  }