lib/botkit/CoreBot.js
function Task(bot, message, botkit) {

    this.convos = [];
    this.botkit = botkit;
    this.bot = bot;

    this.events = {};
    this.source_message = message;
    this.status = 'active';
    this.startTime = new Date();

    this.isActive = function () {
      return this.status == 'active';
    };

    this.createConversation = function (message) {
      var convo = new Conversation(this, message);
      convo.id = botkit.convoCount++;
      this.convos.push(convo);
      return convo;
    };

    this.startConversation = function (message) {

      var convo = this.createConversation(message);
      botkit.logger.debug('>   [Start] ', convo.id, ' Conversation with ', message.user, 'in', message.channel);

      convo.activate();
      return convo;
    };

    this.conversationEnded = function (convo) {
      botkit.logger.debug('>   [End] ', convo.id, ' Conversation with ',
        convo.source_message.user, 'in', convo.source_message.channel);
      this.trigger('conversationEnded', [convo]);
      this.botkit.trigger('conversationEnded', [bot, convo]);
      convo.trigger('end', [convo]);
      var actives = 0;
      for (var c = 0; c < this.convos.length; c++) {
        if (this.convos[c].isActive()) {
          actives++;
        }
      }
      if (actives == 0) {
        this.taskEnded();
      }

    };

    this.endImmediately = function (reason) {

      for (var c = 0; c < this.convos.length; c++) {
        if (this.convos[c].isActive()) {
          this.convos[c].stop(reason || 'stopped');
        }
      }

    };

    this.taskEnded = function () {
      botkit.logger.debug('[End] ', this.id, ' Task for ',
        this.source_message.user, 'in', this.source_message.channel);

      this.status = 'completed';
      this.trigger('end', [this]);

    };

    this.on = function (event, cb) {
      botkit.logger.debug('Setting up a handler for', event);
      var events = event.split(/\,/g);
      for (var e in events) {
        if (!this.events[events[e]]) {
          this.events[events[e]] = [];
        }
        this.events[events[e]].push(cb);
      }
      return this;
    };

    this.trigger = function (event, data) {
      if (this.events[event]) {
        for (var e = 0; e < this.events[event].length; e++) {
          var res = this.events[event][e].apply(this, data);
          if (res === false) {
            return;
          }
        }
      }
    };


    this.getResponsesByUser = function () {

      var users = {};

      // go through all conversations
      // extract normalized answers
      for (var c = 0; c < this.convos.length; c++) {

        var user = this.convos[c].source_message.user;
        users[this.convos[c].source_message.user] = {};
        var convo = this.convos[c];
        users[user] = convo.extractResponses();
      }

      return users;

    };

    this.getResponsesBySubject = function () {
      var answers = {};

      // go through all conversations
      // extract normalized answers
      for (var c = 0; c < this.convos.length; c++) {
        var convo = this.convos[c];

        for (var key in convo.responses) {
          if (!answers[key]) {
            answers[key] = {};
          }
          answers[key][convo.source_message.user] = convo.extractResponse(key);
        }
      }

      return answers;
    };

    this.tick = function () {

      for (var c = 0; c < this.convos.length; c++) {
        if (this.convos[c].isActive()) {
          this.convos[c].tick();
        }
      }
    };
  }
function Task(bot, message, botkit) {

    this.convos = [];
    this.botkit = botkit;
    this.bot = bot;

    this.events = {};
    this.source_message = message;
    this.status = 'active';
    this.startTime = new Date();

    this.isActive = function () {
      return this.status == 'active';
    };

    this.createConversation = function (message) {
      var convo = new Conversation(this, message);
      convo.id = botkit.convoCount++;
      this.convos.push(convo);
      return convo;
    };

    this.startConversation = function (message) {

      var convo = this.createConversation(message);
      botkit.logger.debug('>   [Start] ', convo.id, ' Conversation with ', message.user, 'in', message.channel);

      convo.activate();
      return convo;
    };

    this.conversationEnded = function (convo) {
      botkit.logger.debug('>   [End] ', convo.id, ' Conversation with ',
        convo.source_message.user, 'in', convo.source_message.channel);
      this.trigger('conversationEnded', [convo]);
      this.botkit.trigger('conversationEnded', [bot, convo]);
      convo.trigger('end', [convo]);
      var actives = 0;
      for (var c = 0; c < this.convos.length; c++) {
        if (this.convos[c].isActive()) {
          actives++;
        }
      }
      if (actives == 0) {
        this.taskEnded();
      }

    };

    this.endImmediately = function (reason) {

      for (var c = 0; c < this.convos.length; c++) {
        if (this.convos[c].isActive()) {
          this.convos[c].stop(reason || 'stopped');
        }
      }

    };

    this.taskEnded = function () {
      botkit.logger.debug('[End] ', this.id, ' Task for ',
        this.source_message.user, 'in', this.source_message.channel);

      this.status = 'completed';
      this.trigger('end', [this]);

    };

    this.on = function (event, cb) {
      botkit.logger.debug('Setting up a handler for', event);
      var events = event.split(/\,/g);
      for (var e in events) {
        if (!this.events[events[e]]) {
          this.events[events[e]] = [];
        }
        this.events[events[e]].push(cb);
      }
      return this;
    };

    this.trigger = function (event, data) {
      if (this.events[event]) {
        for (var e = 0; e < this.events[event].length; e++) {
          var res = this.events[event][e].apply(this, data);
          if (res === false) {
            return;
          }
        }
      }
    };


    this.getResponsesByUser = function () {

      var users = {};

      // go through all conversations
      // extract normalized answers
      for (var c = 0; c < this.convos.length; c++) {

        var user = this.convos[c].source_message.user;
        users[this.convos[c].source_message.user] = {};
        var convo = this.convos[c];
        users[user] = convo.extractResponses();
      }

      return users;

    };

    this.getResponsesBySubject = function () {
      var answers = {};

      // go through all conversations
      // extract normalized answers
      for (var c = 0; c < this.convos.length; c++) {
        var convo = this.convos[c];

        for (var key in convo.responses) {
          if (!answers[key]) {
            answers[key] = {};
          }
          answers[key][convo.source_message.user] = convo.extractResponse(key);
        }
      }

      return answers;
    };

    this.tick = function () {

      for (var c = 0; c < this.convos.length; c++) {
        if (this.convos[c].isActive()) {
          this.convos[c].tick();
        }
      }
    };
  }
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~